StreamReader case sensitive - c#

My program currently reads a text file and compares it with the value in a text box and then tells me how many matches, this currently works.
My query is that it is case sensitive. Is there any way to make it so it doesn't matter whether it is in upper or lower case?
This is my code below:
if (!String.IsNullOrEmpty(CustodianEAddress.Text))
{
for (AddressLength1 = 0; AddressLength1 < Length; AddressLength1++)
{
List<string> list1 = new List<string>();
using (StreamReader reader = new StreamReader(FileLocation))
{
string line1;
//max 500
string[] LineArray1 = new string[500];
while ((line1 = reader.ReadLine()) != null)
{
list1.Add(line1); // Add to list.
if (line1.IndexOf(cust1[AddressLength1].ToString()) != -1)
{
count1++;
LineArray1[count1] = line1;
}
}
reader.Close();
using (System.IO.StreamWriter filed =
new System.IO.StreamWriter(FileLocation, true))
{
filed.WriteLine("");
filed.WriteLine("The email address " +
cust1[AddressLength1].ToString() + " was found " + count1 +
" times within the recipient's inbox");
}
string count1a;
count1a = count1.ToString();
}
}
}
else
{
MessageBox.Show("Please Enter an Email Address");
}
So basically, I need to compare the value in cust1[AddressLength1] with any values found in an array which is in the text file.

String.Compare() takes in an optional parameter that let's you specify whether or not the equality check should be case sensitive.
Edited in response to code being posted
Compare and Index of both take in an optional enumeration, StringComparison. If you choose StringComparison.OrdinalIgnoreCase then case will be ignored.

Here's a quick way to compare two strings without checking case:
string a;
string b;
string.Compare(a, b, true);
The true here is passed as the value of the ignoreCase parameter, meaning that upper and lower-case letters will be compared as if they were all the same case.
EDIT:
I've cleaned up your code a bit, and also put in the compare function. I included comments where I changed stuff:
// Not needed: see below. List<string> list1 = new List<string>();
using (StreamReader reader = new StreamReader(FileLocation))
{
string line1;
//max 500
List<string> LineArray1 = new List<string>();
while ((line1 = reader.ReadLine()) != null)
{
// list1.Add(line1); // Add to list.
// By adding to the list, then searching it, you are searching the whole list for every single new line - you're searching through the same elements multiple times.
if (string.Compare(line1, cust1[AddressLength1].ToString(), true) == 0)
{
// You can just use LineArray1.Count for this instead. count1++;
LineArray1.Add(line1);
}
}
// Not needed: using() takes care of this. reader.Close();
using (System.IO.StreamWriter filed =
new System.IO.StreamWriter(FileLocation, true))
{
filed.WriteLine(); // You don't need an empty string for a newline.
filed.WriteLine("The email address " +
cust1[AddressLength1].ToString() + " was found " + LineArray1.Count +
" times within the recipient's inbox");
}
string count1a;
count1a = LineArray1.Count.ToString();
}

The fact you are reading from a file or not it does not matter, when compare
use the static string Comapare function:
public static int Compare(
string strA,
string strB,
bool ignoreCase
)
and pass true as a last parameter.

Related

Fetch particular string from particular block

I am new to c#. I have text file with data in it but I want to read particular block line data.
Here address can occur multiple times in text file.
Something here...
... ... ...
interface "system"
address 10.4.1.10/32
no shutdown
exit
something here...
... ... ...
address 101.4.1.11/32
but i want to capture within this
interface "system"
address 10.4.1.10/32
no shutdown
exit
I want to capture this ip from the block:
10.4.1.10
I tried this code:
int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
Console.WriteLine (line);
counter++;
}
file.Close();
// Suspend the screen.
Console.ReadLine();
Expected Output:
my expected output is to capture the ip address from that block ie.10.4.1.10
that ip is inside "interface system" block.. that makes that address as unique.. as there can be many ips with keyword address. So i want to take address which is inside interface system block.
Please let me know how i can capture particular string from the block.
Regular Expressions are perfectly suited to handle this type of "problem". The following console app demonstrates how to use Regex to extract the desired IP address from the targeted string block.
private static readonly string IPV4_PATTERN = "[0-9./]";
private static readonly string IPV4_IPV6_PATTERN = "[A-Z0-9:./]";
static void Main(string[] args)
{
TestSearchFile();
}
private static string ParseIpWithRegex(string textToSearch, string startBlock, string endBlock)
{
var pattern = $#"{startBlock}\D*\s*({IPV4_IPV6_PATTERN}+).*{endBlock}";
var ms = Regex.Match(textToSearch, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
if (ms.Groups.TryGetValue("1", out var g))
{
return g.Value;
}
return string.Empty;
}
private static void TestSearchFile()
{
var sep = Environment.NewLine;
var ipAddress6 = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
var ipAddress4 = "10.4.1.10/32";
var t = "Something here..." + sep;
t += "... ... ... " + sep;
t += "interface \"system\"" + sep;
t += "address " + ipAddress4 + sep;
t += "no shutdown" + sep;
t += "exit" + sep;
t += "something here..." + sep;
t += "address 101.4.1.11/32" + sep;
t += "... ... ... " + sep;
var startBlock = "interface \"system\"";
var endBlock = "exit";
var ip = ParseIpWithRegex(t, startBlock, endBlock);
Console.WriteLine($"IP: {ip}");
}
I've included two IP address patterns IPV4_PATTERN for IPV4 only as well as IPV4_IPV6_PATTERN for both IPV4 and IPV6. Select the one you feel is most appropriate. Although the IPV4_IPV6_PATTERN would apply to both IP versions I believe it improves performance slight when the search is narrowed by using the narrowest pattern.
Don't forget to import the Regex reference:
using System.Text.RegularExpressions;
**Code Explained**
The method "ParseIpWithRegex" uses a Regex pattern constructed by using the string that signifies the start of the targeted block and the string that signifies the end of that block. Nestled within that pattern is the regular expressions class definition that defines the IP address pattern we wish to isolate as a group.
$#"{startBlock}\D*\s*({IPV4_IPV6_PATTERN}+).*{endBlock}";
It should be noted that the curly brackets are just for string interpolation and have (in this case) nothing to do with the actual regular expression!
After the "startBlock" we see "\D*". This means that after the "startBlock" include in the search all non-numeric characters (where the "star" indicates to expect zero to infinitely many). Then we see "\s*" which means to include all white space (including new line characters since I included RegexOptions.Singleline).
The IP address pattern is in brackets "()" which instructs Regex to create groups. In this case, behind the IP address pattern (in the above code example IPV4_IPV6_PATTERN) there is a "+" symbol. This indicates that there MUST be at least one of the characters that is in the IP address Regex class definition in order to be considered a "match".
After that we see ".*" in front of the "endBlock". This means to look for any character--including the "new line" character (zero to infinitely many) in from of the "endBlock" string.
If you have any questions, please leave a comment.
EDIT
From your button onclick method you will call SearchFileForIp. You will need to change myTextBox to match your code.
You should also decide whether you will be searching IPV4 or both IPV4 and IPV6 and select the appropriate variable IPV4_PATTERN or IPV4_IPV6_PATTERN.
private void SearchFileForIp()
{
var fileName = "c:\\test.txt";
using var sr = new StreamReader(fileName);
string fileContent = sr.ReadToEnd();
var startBlock = "interface \"system\"";
var endBlock = "exit";
var ip = ParseForIpRegex(fileContent, startBlock, endBlock);
myTextBox.Text = ip; //Change this to match your code
}
private readonly string IPV4_PATTERN = "[0-9./]";
private readonly string IPV4_IPV6_PATTERN = "[A-Z0-9:./]";
private string ParseForIpRegex(string textToSearch, string startBlock, string endBlock)
{
var pattern = $#"{startBlock}\D*\s*({IPV4_PATTERN}+).*{endBlock}";
var ms = Regex.Match(textToSearch, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
if(ms.Groups.Count > 0)
{
return ms.Groups[1].Value;
}
//For .Net Core apps
//if (ms.Groups.TryGetValue("1", out var g))
//{
// return g.Value;
//}
return string.Empty;
}
In addition to the 2 answers with Regex solutions, If address line comes always after interace "system", than a simple for loop can do the job.
interface "system"
address 10.4.1.10/32
no shutdown
exit
So We go thorugh file lines and check if line is interace "system" than take the next value and parse it to string of ip address.
public static string GetIpAddressFromFile(string fileName, string startLine)
{
var lines = File.ReadAllLines(fileName);
var ipAddress = string.Empty;
for (var i = 0; i < lines.Length; i++)
{
var line = lines[i].Trim();
if (line != startLine) continue;
var addressLine = lines[i + 1].Trim().Replace("address", "");
ipAddress = addressLine.Substring(0, addressLine.IndexOf("/", StringComparison.Ordinal));
break;
}
return ipAddress.Trim();
}
Lets assume you that your file is inconsistent and address does not comes first after interface "system"
interface "system"
...
address 10.4.1.10/32
no shutdown
exit
So in this case we put all lines between interface "system" and exit in list of strings, Or dictionary and fetch the address key.
public static string GetIpAddressFromFile(string fileName, string startLine, string endLine)
{
var lines = File.ReadAllLines(fileName);
var ipAddress = string.Empty;
var state = false;
var results = new Dictionary<string, string>();
foreach (var t in lines)
{
var line = t.Trim();
if (line == startLine)
state = true;
if (line == endLine)
state = false;
if (!state) continue;
var s = line.Split(" ");
results.TryAdd(s[0], s[1]);
}
var result = results.GetValueOrDefault("address");
if (result != null)
{
ipAddress = result.Substring(0, result.IndexOf("/", StringComparison.Ordinal));
}
return ipAddress;
}
Usage:
var startLine = "interface \"system\"";
var endLine = "exit";
var ip = GetIpAddressFromFile(#"File.txt", startLine);
//Or
var ip = GetIpAddressFromFile1(#"File.txt", startLine, endLine);
Both methods are tested with your given example and return:
10.4.1.10
If the start of the block and the end of the block are well defined, in order to find the block you can simply:
Search for the start of the block
Do something with the lines until the end of the block
string line;
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null && !line.Equals(START_OF_BLOCK)); // 1.
while((line = file.ReadLine()) != null && !line.Equals(END_OF_BLOCK)) // 2.
{
// do something with the lines
}
file.Close();
Updated answer after edited question:
In order to "extract" the string in a form of an IP address inside the block, you could, for example, use Regular expressions with a .NET Regex class, with previously finding the needed block:
Search for the start of the block
Search for the line inside the block which contains "address"
Extract the IP address from the line using Regexp.Match()
string line;
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
string pat = #"\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b";
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(pat);
while ((line = Console.ReadLine()) != null && !line.Equals(START_OF_BLOCK)); // 1.
while ((line = Console.ReadLine()) != null && !line.Equals(END_OF_BLOCK)) // 2.
{
if (line.Contains("address"))
{
System.Text.RegularExpressions.Match ip = reg.Match(line);
Console.WriteLine(ip);
break; // break if you are sure there's only one ip in that block
}
}
file.Close();
Here is simple LINQ for that:
var textData = File.ReadAllLines("Path goes here");
var address = string.Join("", textData
.SkipWhile(x => !x.Trim().StartsWith($"interface \"system\""))
.SkipWhile(x => !x.Trim().StartsWith($"address"))
.Take(1)).Split("address")[1].Trim();
SkipWhile goes trough string array until it finds line which starts
like: "interface \"system\"".
Second SkipWhile goes trough part after "interface \"system\"" string until
it finds line which starts like: "address".
Then you Take(1) matching line and create string out of it.
Then you use Split to create new array which contains address text
and ip address.
After that you simply take last part of the array.

Unnecessary NullReferenceException? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
Why do I get a NullReferenceException in the following code?
private string FileR ( string name )
{
string[] content = ReadSite(name, Protocol.read, url);
Request_Template newCon;
string[] final = new string[content.Length];
for (int i = 0; i < content.Length; i++)
{
if (content[i].Equals(null))
{
return "content [" + i + "] returns null";
}
newCon = JsonSerializer.Deserialize<Request_Template>(content[i]);
if (newCon.Sender.Contains(myAccount.Username))
{
newCon.Sender = "Me";
}
string sender = newCon.Sender;
string message = newCon.Message;
final[i] = sender + ":\t" + message;
}
string nFinal = string.Concat(final);
Thread.Sleep(10);
return nFinal;
}
string[] ReadSite(string filename, Protocol p, string uri)
{
Read_Template temp = new Read_Template
{
Chat = filename,
Code = key1
};
string myUrl = JsonSerializer.Serialize(temp);
WebClient web = new WebClient();
Stream stream = web.OpenRead(uri + "/" + myUrl);
int length = 0;
while (new StreamReader(stream).ReadLine() != null)
{
length++;
}
string[] content = new string[length];
using (StreamReader reader = new StreamReader(stream))
{
for (int i = 0; i < length; i++)
{
content[i] = reader.ReadLine();
}
}
return content;
}
I've tried using the debugging tools with no avail. When I ran the code, it said that the error came from string [] final = new string [content.Length];
and for (int i = 0; i < content.Length; i++).That lead me to assume that content was null. But when I used the watch window and it said that the variable content cannot be determined. How do I fix this?
I strongly suspect that the problem is actually here:
if (content[i].Equals(null))
If content[i] is genuinely null, then calling content[i].Equals will throw a NullReferenceException. That test should be written as:
if (content[i] is null)`
Or (for C# 6 or older):
if (content[i] == null)`
Now if ReadSite didn't have a bug in, you shouldn't need that check at all - because ReadSite should return an array of non-null string references. However, the way that you're populating the array is broken. You're currently:
Creating a StreamReader around the stream
Reading from the reader until you run out of data
Creating a new array of the "right" length
Creating another StreamReader around the same stream - which is by now at the end
Reading from the reader however many times you read a line originally
Because the stream is already at the end, ReadLine() is going to return null on every iteration.
Instead, you should just read once, populating a list as you go, like this:
List<string> content = new List<string>();
using (var stream = web.OpenRead(uri + "/" + myUrl))
{
using (var reader = new StreamReader(stream))
{
string line;
while ((line = reader.ReadLine()) is object)
{
content.Add(line);
}
}
}
return content;
That's returning a List<string>, so you'd want to change your ReadSite return type to List<string> or perhaps IReadOnlyList<string>. If you really need it to return an array, you could return content.ToArray() instead.
(Ideally, move to using HttpClient as well, but that's a different story.)
private string FileR ( string name )
{
// ReadSite always returns a content that has length 0 or more. string[] content will never equals null.
// TEST: string[] test = new string[0]; test == null -> False
string[] content = ReadSite(name, Protocol.read, url);
Request_Template newCon;
string[] final = new string[content.Length];
// if content.Length == 0, this loop will never occur and you wont get any NREs.
for (int i = 0; i < content.Length; i++)
{
// It is highly unlikely that a reader.ReadLine() would generate a null but
// just in case it does, use == null instead of .Equals() method. When content[i] == null, you cannot use .Equals() method since nulls dont have Equals method.
if (content[i].Equals(null))
{
return "content [" + i + "] returns null";
}
// If you have checked that content[i] is Not empty space or null, you might
//end up with newCon == null if Deserialization fails. Cover this around try / catch.
newCon = JsonSerializer.Deserialize<Request_Template>(content[i]);
// If deserialization fails, this will throw NRE because nulls wont have
// Sender as a property or array. Check if newCon == null or not. Also,
// check if Sender was correctly initialized as an array/list.. as it could
// be null. nulls wont have Contains as a method.
if (newCon.Sender.Contains(myAccount.Username))
{
newCon.Sender = "Me";
}
string sender = newCon.Sender;
string message = newCon.Message;
// This should work correctly as its dependent on content.length. If the
// loop is happening, then there is at least one final element that can be updated.
final[i] = sender + ":\t" + message;
}
string nFinal = string.Concat(final);
Thread.Sleep(10);
return nFinal;
}

C#: add data to dictionary from datafile [duplicate]

So I have a generic number check that I am trying to implement:
public static bool isNumberValid(string Number)
{
}
And I want to read the contents of a textfile (only contains numbers) and check each line for the number and verify it is the valid number using isNumberValid. Then I want to output the results to a new textfile, I got this far:
private void button2_Click(object sender, EventArgs e)
{
int size = -1;
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
string text = File.ReadAllText(file);
size = text.Length;
using (StringReader reader = new StringReader(text))
{
foreach (int number in text)
{
// check against isNumberValid
// write the results to a new textfile
}
}
}
catch (IOException)
{
}
}
}
Kind of stuck from here if anyone can help?
The textfile contains several numbers in a list:
4564
4565
4455
etc.
The new textfile I want to write would just be the numbers with true or false appended to the end:
4564 true
You don't need to read the entire file into memory all at once. You can write:
using (var writer = new StreamWriter(outputPath))
{
foreach (var line in File.ReadLines(filename)
{
foreach (var num in line.Split(','))
{
writer.Write(num + " ");
writer.WriteLine(IsNumberValid(num));
}
}
}
The primary advantage here is a much smaller memory footprint, as it only loads a small part of the file at a time.
You could try this to keep with the pattern you were initially following...
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
using (var reader = new StreamReader(file))
{
using (var writer = new StreamWriter("results.txt"))
{
string currentNumber;
while ((currentNumber = reader.ReadLine()) != null)
{
if (IsNumberValid(currentNumber))
writer.WriteLine(String.Format("{0} true", currentNumber));
}
}
}
}
catch (IOException)
{
}
}
}
public bool IsNumberValid(string number)
{
//Whatever code you use to check your number
}
You need to replace your loop to look like this:
string[] lines = File.ReadAllLines(file);
foreach (var s in lines)
{
int number = int.Parse(s);
...
}
This would read each line of file, assuming that there is only one number per line,
and lines are separated with CRLF symbols. And parse each number to integer, assuming that integer is not greater than 2,147,483,647 and not less than -2,147,483,648, and integers are stored in your locale settings, with or without group separators.
In case if any line is empty, or contains non-integer - code will throw an exception.
You could try something like this:
FileStream fsIn = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
using (StreamReader sr = new StreamReader(fsIn))
{
line = sr.ReadLine();
while (!String.IsNullOrEmpty(line)
{
line = sr.ReadLine();
//call isNumberValid on each line, store results to list
}
}
Then print the list using FileStream.
As other people have mentioned, your isNumberValid method could make use of the Int32.TryParse method, but since you said your text file only contains numbers this may not be necessary. If you're just trying to match the number exactly, you can use number == line.
First, load all lines of the input file in a string array,
then open the output file and loop over the array of strings,
Split each line at the space separator and pass every part to your static method.
The static method use Int32.TryParse to determine if you have a valid integer or not without throwing an exception if the input text is not a valid Int32 number.
Based on the result of the method write to the output file the desidered text.
// Read all lines in memory (Could be optimized, but for this example let's go with a small file)
string[] lines = File.ReadAllLines(file);
// Open the output file
using (StringWriter writer = new StringWriter(outputFile))
{
// Loop on every line loaded from the input file
// Example "1234 ABCD 456 ZZZZ 98989"
foreach (string line in lines)
{
// Split the current line in the wannabe numbers
string[] numParts = line.Split(' ');
// Loop on every part and pass to the validation
foreach(string number in numParts)
{
// Write the result to the output file
if(isNumberValid(number))
writer.WriteLine(number + " True");
else
writer.WriteLine(number + " False");
}
}
}
// Receives a string and test if it is a Int32 number
public static bool isNumberValid(string Number)
{
int result;
return Int32.TryParse(Number, out result);
}
Of course this works only if your definition of 'number' is equal to the allowed values for a Int32 datatype

Copying CSV file while reordering/adding empty columns

Copying CSV file while reordering/adding empty columns.
For example if ever line of incoming file has values for 3 out of 10 columns in order different from output like (except first which is header with column names):
col2,col6,col4 // first line - column names
2, 5, 8 // subsequent lines - values for 3 columns
and output expected to have
col0,col1,col2,col3,col4,col5,col6,col7,col8,col9
then output should be "" for col0,col1,col3,col5,col7,col8,col9,and values from col2,col4,col4 in the input file. So for the shown second line (2,5,8) expected output is ",,2,,5,,8,,,,,"
Below code I've tried and it is slower than I want.
I have two lists.
The first list filecolumnnames is created by splitting a delimited string (line) and this list gets recreated for every line in the file.
The second list list has the order in which the first list needs to be rearranged and re concatenated.
This works
string fileName = "F:\\temp.csv";
//file data has first row col3,col2,col1,col0;
//second row: 4,3,2,1
//so on
string fileName_recreated = "F:\\temp_1.csv";
int count = 0;
const Int32 BufferSize = 1028;
using (var fileStream = File.OpenRead(fileName))
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize))
{
String line;
List<int> list = new List<int>();
string orderedcolumns = "\"\"";
string tableheader = "col0,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10";
List<string> tablecolumnnames = new List<string>();
List<string> filecolumnnames = new List<string>();
while ((line = streamReader.ReadLine()) != null)
{
count = count + 1;
StringBuilder sb = new StringBuilder("");
tablecolumnnames = tableheader.Split(',').ToList();
if (count == 1)
{
string fileheader = line;
//fileheader=""col2,col1,col0"
filecolumnnames = fileheader.Split(',').ToList();
foreach (string col in tablecolumnnames)
{
int index = filecolumnnames.IndexOf(col);
if (index == -1)
{
sb.Append(",");
// orderedcolumns=orderedcolumns+"+\",\"";
list.Add(-1);
}
else
{
sb.Append(filecolumnnames[index] + ",");
//orderedcolumns = orderedcolumns+ "+filecolumnnames["+index+"]" + "+\",\"";
list.Add(index);
}
// MessageBox.Show(orderedcolumns);
}
}
else
{
filecolumnnames = line.Split(',').ToList();
foreach (int items in list)
{
//MessageBox.Show(items.ToString());
if (items == -1)
{
sb.Append(",");
}
else
{
sb.Append(filecolumnnames[items] + ",");
}
}
//expected format sb.Append(filecolumnnames[3] + "," + filecolumnnames[2] + "," + filecolumnnames[2] + ",");
//sb.Append(orderedcolumns);
var result = String.Join (", ", list.Select(index => filecolumnnames[index]));
}
using (FileStream fs = new FileStream(fileName_recreated, FileMode.Append, FileAccess.Write))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(sb.ToString());
}
}
I am trying to make it faster by constructing a string orderedcolumns and remove the second for each loop which happens for every row and replace it with constructed string.
so if you uncomment the orderedcolumns string construction orderedcolumns = orderedcolumns+ "+filecolumnnames["+index+"]" + "+\",\""; and uncomment the append sb.Append(orderedcolumns); I am expecting the value inside the constructed string but when I append the orderedcolumns it is appending the text i.e.
""+","+filecolumnnames[3]+","+filecolumnnames[2]+","+filecolumnnames[1]+","+filecolumnnames[0]+","+","+","+","+","+","+","
i.e. I instead want it to take the value inside the filecolumnnames[3] list and not the filecolumnnames[3] name itself.
Expected value: if that line has 1,2,3,4
I want the output to be 4,3,2,1 as filecolumnnames[3] will have 4, filecolumnnames[2] will have 3..
String.Join is the way to construct comma/space delimited strings from sequence.
var result = String.Join (", ", list.Select(index => filecolumnnames[index]);
Since you are reading only subset of columns and orders in input and output don't match I'd use dictionary to hold each row of input.
var row = tablecolumnnames
.Zip(line.Split(','), (Name,Value)=> new {Name,Value})
.ToDictionary(x => x.Name, x.Value);
For output I'd fill sequence from defaults or input row:
var outputLine = String.Join(",",
filecolumnnames
.Select(name => row.ContainsKey(name) ? row[name] : ""));
Note code is typed in and not compiled.
orderedcolumns = orderedcolumns+ "+filecolumnnames["+index+"]" + "+\",\""; "
should be
orderedcolumns = orderedcolumns+ filecolumnnames[index] + ",";
you should however use join as others have pointed out. Or
orderedcolumns.AppendFormat("{0},", filecolumnnames[index]);
you will have to deal with the extra ',' on the end

Having trouble understanding reading text files in C#

So i'm in my 1st year of college, C# in Visual Studio is one of six modules.
Basically my problem is, i need to read in a value that's in a .txt file and calculate commission from that value.
The .txt file consists of:
1,Pat Ryan,280
2,Mary Smith,300
3,Tom Lynch,20
The 3rd value on each line is what i need to calculate the commission but i can't wrap my head around getting that value since you can't just pick out a value with the code we are currently using, you need to go through each line to get to the next.
This is what i've done so far. I tried doing the calculations this way:
if (columns [0] < 1000) {commission = column[0] * .05}
But get an error:
"Operator '<' cannot be applied to operands of type 'string[]' and 'int'"
Any help would be greatly appreciated!
static void salesReport()
{
string path = "sales.txt";
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
StreamReader salesReport = new StreamReader(fs);
string inputText = salesReport.ReadLine();
Console.WriteLine("{0,-15}{1,-30}{2,-20}\n", "Number","Name","Sales");
while (inputText != null)
{
string[] columns = new string [3];
columns = inputText.Split(',');
Console.WriteLine("{0,-15}{1,-30}{2,-10}\n", columns[0], columns[1], columns[2]);
inputText = salesReport.ReadLine();
}
}
You cannot perform a comparison operation between a string and int as specified in your error. You will need to cast the value you get from the text file to int and then do a comparison.
if (Convert.ToInt32(columns[2]) < 1000)
{
commission = Convert.ToInt32(columns[2]) / .05;
}
Looks like you want the 3rd column, I have changed the index to 2.
here is a quick example of trying to parse a file and do what you want. This has a lot of bad practices, such has the way I am concatenating the output string, but you should get the idea.
static void Main(string[] args)
{
using (StreamReader reader = new StreamReader(#"C:\Path\To\File.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] stuff = line.Split(',');
int id = Convert.ToInt32(stuff[0]);
string name = stuff[1];
int val = Convert.ToInt32(stuff[2]);
double commission = (double)val * 0.05;
Console.WriteLine(name + "'s Commission: " + commission.ToString());
}
}
}
Your issue is that you are not evaluating an integer. You are attempting to apply your comparison operator to the string representation after the split operation.
I added a method safeToInt which will prevent pesky exceptions if the string is not an int. Of course, if you want to be aware of those errors, you should just use Int32.TryParse directly and evaluate the boolean result.
I did not change your code to use the method I added for you :-) You should be able to figure that out.
static void salesReport() {
string path = "sales.txt";
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
StreamReader salesReport = new StreamReader(fs);
string inputText = salesReport.ReadLine();
Console.WriteLine("{0,-15}{1,-30}{2,-20}\n", "Number","Name","Sales");
while (inputText != null) {
string[] columns = new string [3];
columns = inputText.Split(',');
Console.WriteLine("{0,-15}{1,-30}{2,-10}\n", columns[0], columns[1], columns[2]);
inputText = salesReport.ReadLine();
}
}
static int safeToInt(string input, int defaultValue = 0){
int result = 0;
if(Int32.TryParse(input, out result)){
return result;
}
return defaultValue;
}
Try this
if (int.Parse(columns[0]) < 1000) {commission = int.Parse(columns[0]) * .05}​

Categories