I'm trying to read data from a file, split the data and save to array. The code works fine except for the split. It is returning a NullException.
Any help would be greatly appreciated.
public static void LoadHandData(CurrentHand[] handData, string fileName)
{
string input = ""; //temporary variable to hold one line of data
string[] cardData; //temporary array to hold data split from input
StreamReader readHand = new StreamReader(fileName);
for (int counter = 0; counter < handData.Length; counter++)
{
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
int index = 0;
handData[counter].cardSuit = Convert.ToChar(cardData[index++]);
handData[counter].cardValue = Convert.ToInt16(cardData[index++]);
}
readHand.Close();
}
As per the comments, you've only got one line of data. But look at your loop:
for (int counter = 0; counter < handData.Length; counter++)
{
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
int index = 0;
handData[counter].cardSuit = Convert.ToChar(cardData[index++]);
handData[counter].cardValue = Convert.ToInt16(cardData[index++]);
}
That's trying to read one line per hand. On the second iteration, ReadLine will return null, so when you call input.Split() you'll end up with the NullReferenceException you're seeing.
You need to read the line once and split it. Given that you've only got one line of text, you can just use File.ReadAllText to simplify things:
string input = File.ReadAllText(fileName);
string[] cardData = input.Split(' ');
for (int counter = 0; counter < handData.Length; counter++)
{
handData[counter].cardSuit = Convert.ToChar(cardData[counter * 2]);
handData[counter].cardValue = Convert.ToInt16(cardData[counter * 2 + 1]);
}
Related
I have a piece of code that is supposed to streamread this text file:
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
1.1.1.2.2.2.2.1.1.1.2.2.1.1.1
1.2.2.2.2.2.2.2.2.2.2.2.2.1.1
1.1.2.2.2.2.2.2.2.2.2.2.2.1.1
1.1.2.2.2.2.2.2.2.2.2.2.1.1.1
1.1.1.1.2.2.2.2.2.2.2.2.1.1.1
1.1.1.1.2.2.2.2.2.2.1.1.1.1.1
1.1.1.1.1.1.2.2.2.1.1.1.1.1.1
1.1.1.1.1.1.1.2.1.1.1.1.1.1.1
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
1.1.1.1.1.1.1.1.1.1.2.2.1.1.1
1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
Everything is going fine, kinda of. My purpose was to rummage through all the characters one by one, then after that's done start on a new line. This is where my little problem occurs, which I've been trying to fix all night.
It reads the first line nicely, but then it doesn't read the second line...
Here is the code:
System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Text\TextFile.txt");
int loadX = 0;
int loadY = 0;
string line;
while (true)
{
if (loadX <= 12)
{
loadX++;
while ((line = file.ReadLine()) != null)
{
System.Threading.Thread.Sleep(500);
string[] entries = line.Split('.');
System.Console.Write(entries[loadX]);
loadY++;
}
}
System.Threading.Thread.Sleep(500);
Console.Write($" Finished {loadX}");
loadX = 0;
}
var lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
var points = lines.SelectMany((l, x) => l.Split('.').Select((s, y) => new {X = x, Y = y, Value = s}));
foreach (var point in points)
{
Console.WriteLine($"({point.X}, {point.Y})={point.Value}");
}
Using a while loop and StremReader seems so silly when you have easier and more readable ways of handling this.
You can easily simplify your code by doing File.ReadAllLines()
//lines will be a string array
var lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
for(int x = 0; x < lines .Length; x++)
{
var cols = lines [x].Split('.');
for(int y = 0; y < cols.Length; x++)
{
//Here you have access to the value, and the x and y position
Console.WriteLine("x: {0}, y: {1} value: {2}", x, y, cols[y]);
}
}
Demo here
If you want to go through every number in this file with X and Y then this is an example how you can do so:
string[] lines = File.ReadAllLines(#"C:\Text\TextFile.txt");
for(int indexY = 0; indexY < lines.Length; indexY++){
string[] lineEntries = lines[indexY].Split('.');
for(int indexX = 0; indexX < lineEntries; indexX++){
// here you have one number by accessing
// it with lineEntries[indexX]
Console.Write(lineEntries[indexX]);
}
Console.WriteLine();
}
You are mistaken to think it is reading the first line. In fact, your current code reads the first value of each line. Due to your input this just happens to be a similar output to what the first line would be, which has lead to your confusion.
Your main loop should be looping through each line, then you can process the line and loop through each value. Which you can then use however you want.
Here is an example:
using(System.IO.StreamReader file = new System.IO.StreamReader(#"C:\Text\TextFile.txt"))
{
int loadX = 0;
int loadY = 0;
string line;
// Loop through each line as you read it.
while ((line = file.ReadLine()) != null)
{
// Split the line to get an array of values.
string[] entries = line.Split('.');
// Loop through each value and process.
for(int i = 0; i < entries.length; i++)
{
string entry = entries[i];
// TODO: Do something with entry.
loadY++;
}
loadX++;
}
}
Obviously in this example loadX and loadY are not being used, but this demonstrates how to correctly increment them so you can use them as needed.
TIP: When using a SteamReader you should ensure you dispose of it correctly, this is best done by including it in a using block.
I'm facing a problem while developing an application.
Basically,
I have a fixed string, let's say "IHaveADream"
I now want to user to insert another string, for my purpose of a fixed length, and then concatenate every character of the fixed string with every character of the string inserted by the user.
e.g.
The user inserts "ByeBye"
then the output would be:
"IBHyaevBeyAeDream".
How to accomplish this?
I have tried with String.Concat and String.Join, inside a for statement, with no luck.
One memory-efficient option is to use a string builder, since both the original string and the user input could potentially be rather large. As mentioned by Kris, you can initialize your StringBuilder capacity to the combined length of both strings.
void Main()
{
var start = "IHaveADream";
var input = "ByeBye";
var sb = new StringBuilder(start.Length + input.Length);
for (int i = 0; i < start.Length; i++)
{
sb.Append(start[i]);
if (input.Length >= i + 1)
sb.Append(input[i]);
}
sb.ToString().Dump();
}
This only safely accounts for the input string being shorter or equal in length to the starting string. If you had a longer input string, you'd want to take the longer length as the end point for your for loop iteration and check that each array index is not out of bounds.
void Main()
{
var start = "IHaveADream";
var input = "ByeByeByeByeBye";
var sb = new StringBuilder(start.Length + input.Length);
var length = start.Length >= input.Length ? start.Length : input.Length;
for (int i = 0; i < length; i++)
{
if (start.Length >= i + 1)
sb.Append(start[i]);
if (input.Length >= i + 1)
sb.Append(input[i]);
}
sb.ToString().Dump();
}
You can create an array of characters and then re-combine them in the order you want.
char[] chars1 = "IHaveADream".ToCharArray();
char[] chars2 = "ByeBye".ToCharArray();
// you can create a custom algorithm to handle
// different size strings.
char[] c = new char[17];
c[0] = chars1[0];
c[1] = chars2[0];
...
c[13] = chars1[10];
string s = new string(c);
var firstString = "Ihaveadream";
var secondString = "ByeBye";
var stringBuilder = new StringBuilder();
for (int i = 0; i< firstString.Length; i++) {
stringBuilder .Append(str[i]);
if (i < secondString.Length) {
stringBuilder .Append(secondStr[i]);
}
}
var result = stringBuilder.ToString();
If you don't care much about memory usage or perfomance you can just use:
public static string concatStrings(string value, string value2)
{
string result = "";
int i = 0;
for (i = 0; i < Math.Max(value.Length, value2.Length) ; i++)
{
if (i < value.Length) result += value[i].ToString();
if (i < value2.Length) result += value2[i].ToString();
}
return result;
}
Usage:
string conststr = "IHaveADream";
string input = "ByeBye";
var result = ConcatStrings(conststr, input);
Console.WriteLine(result);
Output: IBHyaevBeyAeDream
P.S.
Just checked perfomance of both methods (with strBuilder and simple cancatenation) and it appears to be that both of this methods take same time to execute (if you have just one operation). The main reason for it is that string builder take considerable time to initialize while with use of concatenation we don't need that.
But in case if you have to process something like 1500 strings then it's different story and string builder is more of an option.
For 100 000 method executions it showed 85 (str buld) vs 22 (concat) ms respectively.
My Code
I am new in C# and I am making project but I can't make this delete part ..
If I save my data in .txt file in one line, but contain many fixed length record with no delimiter, if each record has fixed length and each field has fixed length and saved in file like this
1ahly2zamalek
how do I delete, for example the record 2zamalek from line with entering to the program id=2?
public team()
{
Team_ID_Len = 5;
Team_Name_Len = 10;
Team_Rec_Len = 15; ;
Team_ID = new char[Team_ID_Len];
Team_Name = new char[Team_Name_Len];
}
Sounds like you're looking for Substring. Give it a start (length of record * how many), and the length (length of record).
Actually, you might want to create the string as string s = part1+part2 where part1 is the substring from 0 till the start of the record, and part2 is the start of the NEXT record, until the end.
Then just save it.
Your number is your delimiter, split with a char array
using System;
using System;
public static class Program
{
public static void Main()
{
string words = "1sdklfjlsdf2lksjdf3sfd4sfd5fsd6fsd7fsd8fsd9sfd10aslkdfj11jklh12hjk";
int deleteRecordId = 11;
string [] split = words.Split(new Char [] {'1', '2','3','4','5','6','7','8','9','0'});
string newString = "";
int j = 0;
for( int i = 0; i < split.Length; i++)
{
if ( j == deleteRecordId)
{
//ignore this record
Console.WriteLine("ignore i = " + i);
j++;
}
else
{
Console.WriteLine("i = " + i);
if(!( split[i] == ""))
{
newString += j + split[i];
j++;
}
}
}
Console.WriteLine(newString);
}
}
then WriteAll to the file
I'm attempting to parse a text file containing data that is being used on a remote FTP server. The data is delimited by an equals sign (=) and I'm attempting to load each row in to two columns in a DataGridView. The code I have written works fine except for when an equals character is thrown into the second column's value. When this happens, regardless of specifying the maximum count as being 2. I'd prefer not to change the delimiter if possible.
Here is the code that is being problematic:
dataGrid_FileContents.Rows.Clear();
char delimiter = '=';
StreamReader fileReader = new StreamReader(fileLocation);
String fileData = fileReader.ReadToEnd();
String[] rows = fileData.Split("\n".ToCharArray());
for(int i = 0; i < rows.Length; i++)
{
String str = rows[i];
String[] items = str.Split(new char[] { delimiter }, 1, StringSplitOptions.RemoveEmptyEntries);
if (items.Length == 2)
{
dataGrid_FileContents.Rows.Add(items[0], items[1]);
}
}
fileReader.Close();
And an example of the file being loaded:
boats=123
cats=234-f
cars==1
It works as intended for the first two rows and then ignores the last row as it ends up creating a String[] with 1 element and two String[]s with zero elements.
Try the following. It will capture the value before and after the first '=', correctly parsing the cars==1 scenario.
String[] items = str.Split(new char[] { delimiter }, 2, stringSplitOptions.None);
A different solution, if you want everything after the first equals then you could approach this problem using string.IndexOf
for(int i = 0; i < rows.Length; i++)
{
String str = rows[i];
int pos = str.IndexOf(delimiter);
if (pos != -1)
{
string first = str.Substring(0, pos-1);
string second = str.Substring(pos + 1);
dataGrid_FileContents.Rows.Add(first, second);
}
}
Just read all items delimeted by '=' in row.
Then iterate over items, and check, that item not empty, than use this prepared data to write
here illustrated snippet
http://dotnetfiddle.net/msVho2
and your snippet can be transformed to something like bellow
dataGrid_FileContents.Rows.Clear();
char delimiter = '=';
using(StreamReader fileReader = new StreamReader(fileLocation))
{
string[] data = new string[2];
while(true)
{
string row = fileReader.ReadLine();
if(row == null)
break;
string[] items = row.Split(delimiter);
int data_index = 0;
foreach(string item in items)
{
if(data_index >= data.Length)
{
//TODO: log warning
break;
}
if(!string.IsNullOrWhiteSpace(item))
{
data[data_index++] = item;
}
}
if(data_index < data.Length)
{
//TODO: log error, only 1 item in row
continue;
}
dataGrid_FileContents.Rows.Add(data[0], data[1]);
}
}
I am parsing my data output, however, my data has return charicters in it (\n). So when I run my code, the array is built and one of the arrays (4) is blank data... I have tried using null, "", and " ". Would anyone know how I can prevent that last array from showing?
char[] returnChar= {'\n' };
string parseText = captcha;
string[] words = parseText.Split(returnChar);
int count = words.Length;
for (int i = 0; i < count; i++)
{
if (words[i] == null)
{
MessageBox.Show("This row is empty: " + i);
}
MessageBox.Show(words[i]);
}
When doing String.Split, define the second parameter - StringSplitOptions.
string[] words =
parseText.Split(returnChar, StringSplitOptions.RemoveEmptyEntries);
This way it will skip over empty elements.