Reading unknown lines with ReadLine - c#

I want to add strings(abc, def,ghi) to a list of type string,
List<string> names = new List<string>();
Reading unknown number of lines till user enters an Enterkey
All the strings are added to the list
when I use a string(line in below example) and assign it the output of Console.ReadLine() and check if its Empty or not
string line;
while ((!string.IsNullOrEmpty(line =Console.ReadLine())))
{
names.Add(line); //This works abc, def,ghi are added to the list
}
But this doesn't work when I directly compare the Output of Console.ReadLine()
while ((!string.IsNullOrEmpty(Console.ReadLine())))
{
names.Add(Console.ReadLine()); //only def is added to the list
}
I could not identify the issue here.

Why not a simple infinite loop with break:
List<string> names = new List<string>();
while (true) {
string line = Console.ReadLine();
if (string.IsNullOrEmpty(line)) // break on Enter - i.e. on empty line
break;
names.Add(line); // otherwise add into the list
}

Consider what Console.ReadLine() does and how your loop works:
while ((!string.IsNullOrEmpty(Console.ReadLine()))) // read abc, but don't do anything with it
{
names.Add(Console.ReadLine()); // read def, add it to the list
}
Your loop is essentially skipping every other line of input, because each iteration of the loop reads two lines of input, but adds only one of those lines to the list. This is precisely why one would store that input in a variable:
string input = Console.ReadLine();
while (!string.IsNullOrEmpty(input))
{
names.Add(input);
input = Console.ReadLine();
}
(Or, if you prefer, the original example you posted. Though personally I find variable assignment in an operation like that to be distasteful, but that's a matter of personal preference.)

In the second example, you're still using names.Add(line) when line has no value. Also, while having the console take an input, that value isn't saved anywhere.
With your edit it takes two inputs instead of just one.

Related

Get only first column values from CSV rows using CSVHelper

I am trying to parse a CSV file and extract the first string in each line, or the first column as it is laid out in MS Excel.
I am using CsvParser with the Read() method returning a string[] to the row variable.
The problem is, it is returning every single value, so my out looks like this for each line:
20070330 00:00 // This is the value I want to reference
0.9312
0.9352
0.9298
0.9343
How can I reference only the values at these positions in the file without putting in a counter to skip the interim values?
using (TextReader reader = File.OpenText(folder))
{
var datesInCsv = new List<string>();
var parsedCsv = new CsvParser(reader);
while (true)
{
var row = parsedCsv.Read();
if (row.IsNullOrEmpty())
{
break;
}
foreach (var date in row)
{
Console.WriteLine(date);
}
Console.ReadLine();
}
}
The CsvHelper library you are using requires you pass a CsvConfiguration instance when you build the instance of a CsvParse class. This is important to let the library understand and correctly parse your line
The most important thing to give is the value for the Delimiter property. In other words the character used to separate one field from the next one.
You should look at your CSV file and put the appropriate value below.
(For this example I have used the semicolon but change it according to your file)
Looking at you code I think also that the configuration SkipEmptyRecords could be used to simplify the code.
using (TextReader reader = File.OpenText(folder))
{
var datesInCsv = new List<string>();
CsvConfiguration config = new CsvConfiguration();
config.Delimiter = ";";
config.SkipEmptyRecords = true;
var parsedCsv = new CsvParser(reader, config);
string[] row = null;
while ((row = parsedCsv.Read()) != null)
{
// This IsNullOrEmpty doesn't exist according
// to Intellisense and the compiler.
// if(row.IsNullOrEmpty)
// At this point the row is an array of strings where the first
// element is the value you are searching for. No need of loops
Console.WriteLine(row[0]);
Console.ReadLine();
}
}
The Read method of the CsvParser instance returns an array of strings after splitting the input line accordingly to your delimiter. At this point you just need to reference the first element of the array without any loop.
You are explicitly printing every value to the console here:
foreach (var date in row)
{
Console.WriteLine(date);
}
This foreach loop iterates over all elemtens of the current row and print them.
Replace the loop with this, which will only print the first element (index 0):
Console.WriteLine(row[0]);
Of course, this can fail if the line was empty, so you need to check for that, too.
You need to "read" the records and pass the argument of the "mapping" you want. Either by index or name.
See here at each section detailed above:
https://joshclose.github.io/CsvHelper/

How to search for specific char in an array and how to then manipulate that index in c#

Okay, so I'm creating a hangman game and everything functions so far, including what I'm TRYING to do in the question.
But it feels like there is a much more efficient method of obtaining the char that is also easier to manipulate the index.
protected static void alphabetSelector(string activeWordAlphabet)
{
char[] activeWord = activeWordAlphabet.ToCharArray();
string activeWordString = new string(activeWord);
Console.WriteLine("If you'd like to guess a letter, enter the letter. \n
If you'd like to guess the word, please type in the word. --- testing answer{0}",
activeWordString);
//Console.WriteLine("For Testing Purposes ONLY");
String chosenLetter = Console.ReadLine();
//Char[] letterFinder = Array.FindAll(activeWord, s => s.Equals(chosenLetter));
//string activeWordString = new string(activeWord);
foreach (char letter in activeWord);
{
if(activeWordString.Contains(chosenLetter))
{
Console.WriteLine("{0}", activeWordString);
Console.ReadLine();
}
else
{
Console.WriteLine("errrr...wrong!");
Console.ReadLine();
}
}
}
I have broken up the code in some areas to prevent the reader from having to scroll sideways. If this is bothersome, please let me know and I'll leave it in the future.
So this code will successfully print out the 'word' whenever I select the correct letter from the random word (I have the console print the actual word so that I can test it successfully each time). It will also print 'wrong' when I choose a letter NOT in the string.
But I feel like I should be able to use the
Array.FindAll(activeWord, ...)
functionality or some other way. But every time I try and reorder the arguments, it gives me all kinds of different errors and tells me to redo my arguments.
So, if you can look at this and find an easier method of searching the actual array for the user-selected 'letter', please help!! Even if it's not using the Array.FindAll method!!
Edit
Okay, it seems like there's some confusion with what I've done and why I've done it.
I'm ONLY printing the word inside that 'if' statement to test and make sure that the foreach{if{}} will actually work to find the char inside the string. But I ultimately need to be able to provide a placeholder for a char that is successfully found, as well as being able to 'cross out' the letter (from the alphabet list not shown here).
It's hangman - surely you guys know what I'm needing it to do. It has to keep track of which letters are left in the word, which letters have been chosen, as well as which letters are left in the entire alphabet.
I'm a 4-day old newb when it comes to programming, so please. . . I'm only doing what I know to do and when I get errors, I comment things out and write more until I find something that works.
Take a look at this demo I put together for you: https://dotnetfiddle.net/eP9TQM
I'd suggest creating a second string for the display string. Use a StringBuilder, and you can replace the characters in it at specific indices while creating the fewest number of stringobjects in the process.
string word = "your word or phrase here";
//Initialize a new StringBuilder that will display the word with placeholders.
StringBuilder display = new StringBuilder(word.Length); //You know the display word is the same length as the original word
display.Append('-', word.Length); //Fill it with placeholders.
So now you have your phrase/word, and a string builder full of characters that need to be discovered.
Go ahead and convert the display StringBuilder to a string that you can check on each pass to see if it equals your word:
var displayString = display.ToString();
//Loop until the display string is equal to the word
while (!displayString.Equals(word))
{
//Inside here your logic will follow.
}
So you are basically looping until the person answers here. You could of course go back and add logic to limit the number of attempts, or whatever you desire as an alternate exit strategy.
Inside this logic, you will check if they guessed a letter or a word based on how many characters they entered.
If they guessed a word, the logic is simple. Check if the guessed word is the same as the hidden word. If it is, then you break the loop and they are done. Otherwise, guessing loops back around.
If they guessed a letter, the logic is pretty straightforward, but more involved.
First get the character they guessed, just because it may be easier to work with this way.
char guess = input[0];
Now, look over the word for instances of that character:
//Look for instances of the character in the word.
for (int i = 0; i < word.Length; ++i)
{
//If the current index in the word matches their guess, then update the display.
if (char.ToUpperInvariant(word[i]) == char.ToUpperInvariant(guess))
display[i] = word[i];
}
The comments above should explain the idea here.
Update your displayString at the bottom of the loop so that it will check against the hidden word again:
displayString = display.ToString();
That's really all you need to do here. No fancy Linq needed.
Ok your code is really confusing, even with your edit.
First, why these 2 lines of code since activeWordAlphabet is a string :
char[] activeWord = activeWordAlphabet.ToCharArray();
string activeWordString = new string(activeWord);
Then you do your foreach.
For the word "FooBar", if the player types 'F', you will print
FooBar
FooBar
FooBar
FooBar
FooBar
FooBar
How does this help you in anything?
I think you have to review your algorithm. The string type have the function you need
int chosenLetterPosition = activeWord.IndexOf(chosenLetter, alreadyFoundPosition)
alreadyFoundPosition is an int from where the function will search the letter
IndexOf() returns -1 if the letter is not find or a positive number.
You can save this position with your letter in a dictionary to use it again as your new 'alreadyFoundPosition' if the chosenLetter is already in the dictionary
This is my answer. Because I don't have a lot of tasks today :)
class Letter
{
public bool ischosen { get; set; }
public char value { get; set; }
}
class LetterList
{
public LetterList(string word)
{
_lst = new List<Letter>();
word.ToList().ForEach(x => _lst.Add(new Letter() { value = x }));
}
public bool FindLetter(char letter)
{
var search = _lst.Where(x => x.value == letter).ToList();
search.ForEach(x=>x.ischosen=true);
return search.Count > 0 ? true : false;
}
public string NotChosen()
{
var res = "";
_lst.Where(x => !x.ischosen).ToList().ForEach(x => { res += x.value; });
return res;
}
List<Letter> _lst;
}
How to use
var abc = new LetterList("abcdefghijklmnopqrstuvwxyz");
var answer = new LetterList("myanswer");
Console.WriteLine("This my question. Why? write your answer please");
char x = Console.ReadLine()[0];
if (answer.FindLetter(x))
{
Console.WriteLine("you are right!");
}
else
{
Console.WriteLine("fail");
}
abc.FindLetter(x);
Console.WriteLine("not chosen abc:{0} answer:{1}", abc.NotChosen(), answer.NotChosen());
At least we used to play this game like that when i was a child.

Reading a specific line from a csv file and letting the line vary

I need to take 1 line from a CSV file and need the line number to be able to vary. I can make an int, double, string etc. and I can change the value from an outer program easily but I don't know how make a file reader script take one of those as the input for the line number.
string GetLine(string lineresults, int LineNumber)
{
using (var sr = new StreamReader(lineresults)) {
for (int i = 1; i < line; i++)
sr.ReadLine();
return sr.ReadLine();
}
}
And I get errors on the GetLine part for semicolons and closeparens expected
If you want random access you can read all lines and store them in an array, so File.ReadAllLines (remember that your variable LineNumber starts at 0):
string[] allLines = File.ReadAllLines(pathToFile);
string line = allLines[LineNumber]; // error if less lines, check allLines.Length
Another more efficient approach is to use File.ReadLines which lazy loads the lines, then use Enumerable.ElementAt or ElementAtOrDefault to access the line number:
var lines = File.ReadLines(pathToFile);
string line = lines.ElementAtOrDefault(LineNumber); // null if there are less lines
It is worth noting that it reads the file until the line number or the end of the file was reached.
MSDN:
The ReadLines and ReadAllLines methods differ as follows: When you use
ReadLines, you can start enumerating the collection of strings before
the whole collection is returned; when you use ReadAllLines, you must
wait for the whole array of strings be returned before you can access
the array. Therefore, when you are working with very large files,
ReadLines can be more efficient
As #Alex K commented simply read all the lines into an Array and then get the line you are after.
var lines = System.IO.File.ReadAllLines( filename);
var line = lines[ lineIndex ];
This NuGet package is super-duper helpful for working with CSVs. You can grab individual lines from it, and individual columns by either name or index. Check out info here:
[Josh Close - CsvHelper][1]

Split string into array then loop, in C#

I have Googled this a LOT but my C# skills are pretty terrible and I just can't see why this isn't working.
I have a string which comes from a session object, which I don't have any control over setting. The string contains some sentences separated by six underscores. e.g.:
Sentence number one______Sentence number two______Sentence number three etc
I want to split this string by the six underscores and return each item in the resultant array.
Here's the code I have:
string itemsPlanner = HttpContext.Current.Session["itemsPlanner"].ToString();
string[] arrItemsPlanner = itemsPlanner.Split(new string[] { "______" }, StringSplitOptions.None);
foreach (string i in arrItemsPlanner)
{
newItemsPlanner += "debug1: " + i; //This returns what looks like a number, as I'd expect, starting at zero and iterating by one each loop.
int itemNumber;
try
{
itemNumber = Convert.ToInt32(i);
string sentence = arrItemsPlanner[itemNumber].ToString();
}
catch (FormatException e)
{
return "Input string is not a sequence of digits.";
}
catch (OverflowException e)
{
return "The number cannot fit in an Int32.";
}
finally
{
return "Fail!"
}
}
Whenever I run this, the session is being retreived successfully but the line which says: itemNumber = Convert.ToInt32(i); fails every time and I get an error saying "Input string is not a sequence of digits."
Can anyone point me in the right direction with this please?
Many thanks!
If you just want to get each sentence and do something with it, this will do the trick:
string itemsPlanner = HttpContext.Current.Session["itemsPlanner"].ToString();
string[] arrItemsPlanner = itemsPlanner.Split("______");
foreach (string i in arrItemsPlanner)
{
// Do something with each sentence
}
You can split over a string as well as char (or char[]). In the foreach 'i' will be the value of the sentence, so you can concatenate it or process it or do whatever :)
If I've misunderstood, my apologies. I hope that helps :)
in your case i is not a number, it's the actual element in the array. A foreach loop has no iteration variable, you only have access to the actual element being iterated through i.
So first loop itareation i is Sentence number one, then Sentence number two.
If you want the number, you have to use a for loop instead.
So something like this
for( int i = 0; i < arrItemsPlanner.length; i++ ){
//on first iteration here
//i is 0
//and arrItemsPlanner[i] id "Sentence number one"
}
Hope it helps.
From your example i does not contain a valid integer number, thus Convert.ToInt32 fails. The foreach loop sets i with the current item in the sentences array, so basically i always contains one of the sentences in your main string. If you want i to be the index in the array, use a for loop.
Example from MSDN.
string words = "This is a list of words______with a bit of punctuation" +
"______a tab character.";
string [] split = words.Split(new Char [] {'_'}, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in split) {
if (s.Trim() != "")
Console.WriteLine(s);
}
Do you need to trim your string before converting to a number? if thats not you may want to use Int32.tryParse()
In your sample code foreach (string i in arrItemsPlanner) 'i' will get the string value of arrItemsPlanner one by one.
For exmaple on first iteration it will have 'Sentence number one' which is obviously not a vlid ont, hence your conversion failed.
i only contains one of the string fragment which will be : number one Sentence number two and Sentence number three. If you want it to contain an int representing ht index, use :
1) a for loop
2) an int defined before your foreach and increase it (myInt++) in the foreach code !

Search for a keyword in C# and output the line as a string

How would it be possible to search for a string e.g. #Test1 in a text file and then output the line below it as a string e.g.
Test.txt
#Test1
86/100
#Test2
99/100
#Test3
13/100
so if #Test2 was the search keyword "99/200" would be turned into a string
Parse the file once, store the results in a dictionary. Then lookup in the dictionary.
var dictionary = new Dictionary<string, string>();
var lines = File.ReadLines("testScores.txt");
var e = lines.GetEnumerator();
while(e.MoveNext()) {
if(e.Current.StartsWith("#Test")) {
string test = e.Current;
if(e.MoveNext()) {
dictionary.Add(test, e.Current);
}
else {
throw new Exception("File not in expected format.");
}
}
}
Now you can just say
Console.WriteLine(dictionary["#Test1"]);
etc.
Also, long-term, I recommend moving to a database.
Use readline and search for the string (ex. #Test1) and then use the next line as input.
If the exactly above is the file format. Then you can use this
1. read all lines till eof in an array.
2. now run a loop and check if the string[] is not empty.
Hold the value in some other array or list.
now you have items one after one. so whenever you use loop and use [i][i+1],
it will give you the test number and score.
Hope this might help.
How about RegularExpressions? here's a good example
This should do it for you:
int lineCounter = 0;
StreamReader strReader = new StreamReader(path);
while (!strReader.EndOfStream)
{
string fileLine = strReader.ReadLine();
if (Regex.IsMatch(fileLine,pattern))
{
Console.WriteLine(pattern + "found in line " +lineCounter.ToString());
}
lineCounter++;
}

Categories