How to loop a Console.ReadLine? - c#

I cannot figure out how to read user-input in a loop (with Console.ReadLine). I'm trying to create a note that lets me store what ever the user inputs, and exits if he types exit.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Note myNote = new Note();
Note otherNote = new Note();
myNote.addText("Hi there");
Console.WriteLine(myNote.display());
otherNote.addText(Console.ReadLine());
Console.WriteLine(otherNote.display());
if (otherNote = "exit")
{
}
}
}
}
class Note
{
private string text = "";
private DateTime timeStamp = DateTime.Now;
private DateTime modifiedStamp = DateTime.Now;
int maxLength = 10;
public void addText(string sometext)
{
if (text.Length + sometext.Length < maxLength)
{
text += sometext;
modifiedStamp = DateTime.Now;
}
}
public string display()
{
return "Created: " + timeStamp.ToString() + "\n" +
"Modified: " + modifiedStamp.ToString() + "\n" +
"Content: " + text;
}
}

You need List of Notes in order to add as many notes as you want.
Additionally, you need to first save ReadLine input check if the user really asked to exit otherwise keep adding notes.
var myNotes = new List<Note>();
var firstNote = new Note();
firstNote.addText("Hi there");
Note note;
while (true)
{
var input = Console.ReadLine();
if (input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
note = new Note();
note.addText(input);
myNotes.Add(note);
}

The general format is to use something like this (a while loop with a break condition):
// put code above while loop that only needs to be executed once
while (true) {
// get the user input for every iteration, allowing to exit at will
String line = Console.ReadLine();
if (line.Equals("exit")) {
// exit the method.
return; // use "break" if you just want to exit the loop
}
// this is what will happen in the loop body since we didn't exit
// put whatever note stuff you want to execute again and again in here
}
You'll want to edit what goes into the body of this loop depending on what exactly you want done with your note instances. But generally, you repeatedly prompt a user for input until some condition is met and then you break out of the loop. You may decided that condition (e.g. "enter 10 notes"; "type exit"; etc.)

Per #n0rd's comment, here's how a do...while loop could work:
string input;
var myNotes = new List<Note>();
do{
input = Console.ReadLine();
if (!input.Equals("exit", StringComparison.OrdinalIgnoreCase)){
var note = new Note();
note.addText(input);
myNotes.Add(note);
}
} while (!input.Equals("exit", StringComparison.OrdinalIgnoreCase));

To loop Console.ReadLine() you can use this
`List<string> al = new List<string>(); //list to store string values
while(true)
{
string f = Console.ReadLine();
if(f == null) //check if string is null or not
{
break;
}
else
al.Add(f); //add strings to list
}`

One way to do it is this:
List<string> simpleList = new List<string> { "Alpha", "Bravo", "Charlie", "Delta", "Echo" }; //Dummy data source
Console.WriteLine("Enter a call sign to find in the list. Press X to exit: "); //Prompt
string callSign;
string exitKey = "x";
while ((callSign = Console.ReadLine().ToLower()) != exitKey)
{ //This is where the "Magic" happens
if (simpleList.Contains(callSign))
{
Console.WriteLine($"\"{callSign}\" exists in our simple list");//Output should the list contain our entry
Console.WriteLine(""); //Not really relevant, just needed to added spacing between input and output
}
else
{
Console.WriteLine($"\"{callSign}\" does not exist in our simple list"); //Output should the list not contain our entry
}
Console.WriteLine("");
Console.WriteLine("Enter a call sign to find in the list. Press X to exit: ");//Prompt
}
The line:
while ((callSign = Console.ReadLine().ToLower()) != exitKey) {
...
is where the loop happens. If the entry does not equal the exitKey, the steps are repeated.

Related

Read from a text file and order the rows (each row int + String)

I'm coding a game for a university project similar to Subway Surfers. I have everything working precisely but my problem comes in a bookmarks option I coded.
When you lose in the game you have to enter a name and this is written and saved on a text file in the format <int score> <string name>, for example:
11245 Lucas
10123 Marco
2394 Ricky
So then in the menu of the game you can select bookmarks and the text file is read and shown on the screen one score under the other with the name that was written in each game.
Now my problem is that I want the bookmarks to be ordered, with the highest on top, but I do not know how I can do that as I have an int and a string in each line and they are related therefore I can't have one file for the scores and one file for the names as therefore when I order the scores I lost the info regarding who achieved each score.
What can I do to solve this?
EDIT:
I'm adding the part of the code related to my question.
This is the method that shows the bookmarks
static void ReadBookmark()
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("BOOKMARKS");
string myfile = #"bookmarks.txt";
if (File.Exists(myfile) == false)
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("NO BOOKMARKS. PLAY SOME GAMES!");
Console.Write("\nPRESS A KEY TO RETURN...");
Console.ReadKey();
}
else
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.Green;
using (StreamReader sr = File.OpenText(myfile))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine($"\t{s}");
}
}
Console.ForegroundColor = ConsoleColor.White;
Console.Write("\n\nPRESS A KEY TO RETURN...");
Console.ReadKey();
}
}
And here is the code where the name and score are written on the file.
public void SaveBookmark(int score, string name)
{
string myfile = #"bookmarks.txt";
using (StreamWriter sw = File.AppendText(myfile))
{
sw.WriteLine($"{score} {name}");
}
}
You can split each line on whitespace and then use int.Parse to get the numeric value of the first part, and then OrderByDescending using that value:
var orderedLines = File.ReadLines(myfile)
.OrderByDescending(line => int.Parse(line.Split()[0]))
.ToList();
Full example of what to do safely, finished before you posted your code.
This will allow the names to have a space in them.
public List<ScoreItem> GetScores()
{
var scoreList = new List<ScoreItem>();
using (var fs = File.OpenRead("myPath"))
using (var sr = new StreamReader(fs))
{
while (!sr.EndOfStream)
{
var line = sr.ReadLine();
if (string.IsNullOrWhiteSpace(line)) continue;
var scoreMatch = Regex.Match(line, #"\A\d*");
if (!scoreMatch.Success)
throw new Exception($"Failed to parse score from line [{line}].");
var nameMatch = Regex.Match(line, #"(?<!\A\d*).*\Z");
if (!nameMatch.Success)
throw new Exception($"Failed to parse name from line [{line}].");
if (!int.TryParse(scoreMatch.Value, out var score))
throw new Exception($"Failed to cast score to a number from line [{line}].");
scoreList.Add(new ScoreItem {Name = nameMatch.Value, Score = score});
}
return scoreList.OrderByDescending(s => s.Score).ToList();
}
}
public class ScoreItem
{
public string Name { get; set; }
public int Score { get; set; }
}

Is there another alternate way to add Console.WriteLine() in this scenario

In this code, I wish to add a Console.Writeline() after each Console.ReadLine() but how I am implementing the code it is giving me an error. Is there another way how I can add Console.WriteLine() in the instance?
public void CreateAccount()
{
Console.WriteLine("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
Console.WriteLine("Create an Account");
Client createAccount = new Client("Create")
{
NameOfUser = Console.ReadLine(),
SurnameOfUser = Console.ReadLine(),
UserID = Console.ReadLine(),
UserEmail = Console.ReadLine(),
UserHomeAdd = Console.ReadLine(),
UserMobileNumber = int.Parse(Console.ReadLine()),
UsernameField = Console.ReadLine(),
PasswordField = Console.ReadLine(),
CoffePoints = int.Parse(Console.ReadLine())
};
List<Client> accountData = new List<Client>()
{
createAccount
};
You could create a method that prints something and returns Console.ReadLine(), for example:
private static string ReadLine(string writeMessage, bool parseAsInt = false)
{
Console.WriteLine(writeMessage);
var line = Console.ReadLine();
if (parseAsInt)
{
int parseInt = 0;
int.TryParse(line, out parseInt);
line = parseInt.ToString();
}
return line;
}
Then just call it when creating the object:
Client createAccount = new Client("Create")
{
NameOfUser = ReadLine("What's your name?"),
SurnameOfUser = ReadLine("Input your surname"),
[...]
CoffePoints = ReadLine("Coffe points?", true)
};
You can't put WriteLine() between your ReadLine(), because you're initializing properties of your new Client. You can, however, do it like this instead:
public void CreateAccount()
{
Console.WriteLine("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
Console.WriteLine("Create an Account");
Client createAccount = new Client("Create");
Console.WriteLine("Enter NameOfUser ");
createAccount.NameOfUser = Console.ReadLine();
Console.WriteLine("Enter SurnameOfUser ");
createAccount.SurnameOfUser = Console.ReadLine();
Console.WriteLine("Enter UserID ");
createAccount.UserID = Console.ReadLine();
Console.WriteLine("Enter UserEmail ");
createAccount.UserEmail = Console.ReadLine();
Console.WriteLine("Enter UserHomeAdd ");
createAccount.UserHomeAdd = Console.ReadLine();
Console.WriteLine("Enter UserMobileNumber ");
createAccount.UserMobileNumber = int.Parse(Console.ReadLine());
Console.WriteLine("Enter UsernameField ");
createAccount.UsernameField = Console.ReadLine();
Console.WriteLine("Enter PasswordField ");
createAccount.PasswordField = Console.ReadLine();
Console.WriteLine("Enter CoffePoints ");
createAccount.CoffePoints = int.Parse(Console.ReadLine());
List<Client> accountData = new List<Client>()
{
createAccount
};
When you appreciate why this works, I'd recommend to do like Isma suggested (if you've been taught about how to make your own methods yet), to make your code cleaner. I wrote this to help you appreciate why what you wrote wasn't working out. Shorthand property initializers like this:
Something s = new Something(){
Property1 = ReadLine(), //no semicolon here, this is all
Property2 = ReadLine() //one line of code in a=1,b=2,c=3 pattern
};
Cannot have multiple lines of code like this:
Something s = new Something(){
Property1 = WriteLine("Blah"); ReadLine(); //can't put a semicolon here
Property2 = WriteLine("Blah"); ReadLine(); //it HAS to be a comma, because it
Property3 = WriteLine("Blah"); ReadLine(); //HAS to be a single line of code
};
Remember that it is not the return key that defines a new line of code in C#, it's the semicolon. It's simply a language rule that the pattern for setting properties like this is single line, and only one statement can appear on the right hand side of the =
You must either not use the shorthand way (as above) or you must put all the multiple lines of code you want to use into a single method, and then call that method (as Isma suggested)
I'd also like to point out that you said you wanted to "writeline a message after every readline" - note that your program will wait for the user to input anything before it prints your message. Isma's way (and this above) print a message BEFORE asking for a readline, because this is more typically what you'd want to do.
If you really do want it after, then move them to be after (but I guess really you can only be thanking them for their input, and overly thankful things are annoying...) so something like this (Isma's way):
private static string ReadLine(string writeMessage)
{
string s = Console.ReadLine();
Console.WriteLine(writeMessage);
return s;
}
or my way:
public void CreateAccount()
{
Console.WriteLine("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
Console.WriteLine("Create an Account");
Client createAccount = new Client("Create");
createAccount.NameOfUser = Console.ReadLine();
Console.WriteLine("Thanks for entering NameOfUser..");

Create list of arrays from text file in C#

I have a number of text files that all follow the same content format:
"Title section","Version of the app"
10
"<thing 1>","<thing 2>","<thing 3>","<thing 4>","<thing 5>","<thing 6>","<thing 7>","<thing 8>","<thing 9>","<thing 10>"
'Where:
' first line never changes, it always contains exactly these 2 items
' second line is a count of how many "line 3s" there are
' line 3 contains a command to execute and (up to) 9 parameters
' - there will always be 10 qoute-delimited entries, even if some are blank
' - there can be N number of entries (in this example, there will be 10 commands to read)
I am reading each of these text files in, using StreamReader, and want to set each file up in its own class.
public class MyTextFile{
public string[] HeaderLine { get; set; }
public int ItemCount { get; set; }
List<MyCommandLine> Commands { get; set;}
}
public class MyCommandLine{
public string[] MyCommand { get; set; }
}
private void btnGetMyFilesiles_Click(object sender, EventArgs e){
DirectoryInfo myFolder = new DirectoryInfo(#"C:\FileSpot");
FileInfo[] myfiles = myfolder.GetFiles("*.ses");
string line = "";
foreach(FileInfo file in Files ){
str = str + ", " + file.Name;
// Read the file and display it line by line.
System.IO.StreamReader readingFile = new System.IO.StreamReader(file.Name);
MyTextFile myFileObject = new MyTextFile()
while ((line = readingFile.ReadLine()) != null){
' create the new MyTextFile here
}
file.Close();
}
}
}
The objective is to determine what the actual command being called is (""), and if any of the remaining parameters point to a pre-existing file, determine if that file exists. My problem is that I can't figure out how to read N number of "line 3" into their own objects and append these objects to the MyTextFile object. I'm 99% certain that I've led myself astray in reading each file line-by-line, but I don't know how to get out of it.
So, addressing the specific issue of getting N number of line 3 items into your class, you could do something like this (obviously you can make some changes so it is more specific to your application).
public class MyTextFile
{
public List<Array> Commands = new List<Array>();
public void EnumerateCommands()
{
for (int i = 0; i < Commands.Count; i++)
{
foreach (var c in Commands[i])
Console.Write(c + " ");
Console.WriteLine();
}
}
}
class Program
{
static void Main(string[] args)
{
string line = "";
int count = 0;
MyTextFile tf = new MyTextFile();
using (StreamReader sr = new StreamReader(#"path"))
{
while ((line = sr.ReadLine()) != null)
{
count += 1;
if (count >= 3)
{
object[] Arguments = line.Split(',');
tf.Commands.Add(Arguments);
}
}
}
tf.EnumerateCommands();
Console.ReadLine();
}
}
At least now you have a list of commands within your 'MyTextFile' class that you can enumerate through and do stuff with.
** I added the EnumerateCommands method so that you could actually see the list is storing the line items. The code should run in a Console application with the appropriate 'using' statements.
Hope this helps.
If all of the is separated with coma sign , you can just do something like :
int length = Convert.ToInt32 (reader.ReadLine ());
string line = reader.ReadLine ();
IEnumerable <string> things = line.Split (',').Select (thing => thing. Replace ('\"'', string.Empty).Take(length);
Take indicates how many things to take from the line.

What is the error with the input of the string that it causes nullreferenceexception?

The problem is with the else case, I have commented on the problem lines
static void Main(string[] args)
{
XMLData xmldataExample = new XMLData();
Usergaz usergazExample = new Usergaz();
UsergazItem usergazitemExample = new UsergazItem();
UsergazItem item = new UsergazItem();
string filename = #"C:\Users\565133\Desktop\test.xml";
Deserialize<XMLData> deserializeobj = new Deserialize<XMLData>();
Console.WriteLine("Choose \n1.Serialization\n2.Deserialization\n3.Deserialize only a token");
//It works when I give tknid input line here
int inp = Console.Read();
string tknid = Console.ReadLine();//It doesn't work if I get tknid input here
if (inp == 1)
{
usergazitemExample.getusergazitem();
usergazExample.getusergaz();
usergazExample.gazitem.Add(usergazitemExample);
xmldataExample.getxmldata();
xmldataExample.gazset.Add(usergazExample);
serial(xmldataExample, filename);
Console.WriteLine("Its done");
Console.ReadKey();
}
else if (inp == 2)
{
Console.WriteLine("Getting data from xml file");
// Deserialize<XMLData> deserializeobj = new Deserialize<XMLData>();
xmldataExample = deserializeobj.deserializefunction(filename);
List<Usergaz> samplelist = new List<Usergaz>();
samplelist = xmldataExample.gazset;
MTable.initialize();
MTable.usergazzetterset.Add(xmldataExample.updatedtime, samplelist);
Console.WriteLine("Deserialization complete, check the object");
Console.ReadKey();
}
In this else case, I'm filtering using tknid, but even before I input tknid from the user, I get nullreference exception saying the 'item' object is null.
I get the exception pointed to the Console.WriteLine Line
else
{
//Console.WriteLine("Getting only a specific token Enter the token id");
//string tknid;
//tknid = Console.ReadLine();
//I intended to give tknid input here, but I cannot do it...
//Console.WriteLine(tknid);
//Console.ReadKey();
//string tknid = "3"; Initializing tknid with this statement works fine
item = deserializeobj.deserializefunction(filename).gazset[0].gazitem.Where(X => X.id == tknid).FirstOrDefault();
Console.WriteLine("The value for the token id {0} is {1}", tknid,item.val);
Console.ReadKey();
}
}
I have got the solution, the problem was not with if..else statement, it's with Console.Read().
I replaced int inp = Console.Read() with int inp = int.Parse(Console.ReadLine()) and it works fine.
Now I understand how Console.Read() works with the help of an answer I have shared below, but I'll never try to use Console.Read(), and would always use Console.ReadLine().
How Console.Read() works:
https://stackoverflow.com/a/10318917/7114583

How do i use threading in this program?

I've written this console application to search for a particular string from a file and see if its present or not.. But i want to open only the file in the main program. And include 10different threads to find 10 different words simultaneously.. I tried using the thread but i didnt get it right.. How do i do it? could someone help me with the code? This is my program..
class Program
{
static void Main(string[] args)
{
Thread T = new Thread(Finding);
T.Start();
using (System.IO.StreamReader Reader = new System.IO.StreamReader("C://myfile2.txt"))
{
StringBuilder Sb = new StringBuilder();
string fileContent = Reader.ReadToEnd();
if (fileContent.Contains("and"))
{
Console.WriteLine("It is Present");
}
else
{
Console.WriteLine("It is not Present");
}
Console.ReadLine();
}
}
static void Finding()
{
if (fileContent.Contains("hello"))
{
Console.WriteLine("It is Present");
}
else
{
Console.WriteLine("It is not Present");
}
}
}
var text = File.ReadAllText("somePath");
foreach (var word in new[]{"word1", "word2", "word3"})
{
var w = word;
new Thread(() => Console.WriteLine("{0}: {1}",
w,
text.Contains(w) ? "Yes" : "No")).Start();
}
You should know that string can't contain infinite characters, so if the content is too big for a string, you could use File.ReadAllLines("path") into "lines" instead of File.ReadAllText("path") into "text" and replace
text.Contains(w)
with
lines.Any(l => l.Contains(w))
You could also do something sophisticated using File.ReadLines() to avoid reading all lines when not necessary, if you believe that all words are likely to be found.

Categories

Resources