How to read/append string in C# with exact spacing/tabs/lines - c#

I have sample data
string test = #"allprojects {
repositories {
test()
}
}"
When I read the test, I should get the exact string with spaces/tabs/new lines instead of me writing Environment.NewLine etc wherever it requires new line. When I print, it should print the same format [WYSIWYG] type.
Presently it gives something like this in debugger allprojects {\r\n\t\t repositories { \r\n\t\t test() \r\n\t\t } \r\n\t\t }

There are several ways to determine a new line, and it is dependant on the OS you are using:
Windows: \r\n
Unix: \n
Mac: \r
As for a tab, all you need is \t.
Therefore, in your string all you need is:
string test = #"allprojects {\r\n\trepositories {\r\n\t\ttest()\r\n\t}\r\n}"
Which will output:
allprojects {
repositories {
test()
}
}

What I do in string literals that need this is just not indent the content at all:
namespace Foo {
class Bar {
const string test = #"
allprojects {
repositories {
test()
}
}";
}
}
And strip away the initial newline. Looks a bit ugly, but it does get the point across that the leading whitespace matters.
You can also place the #" on the second chance, but automatic code formatting could move that and it doesn't look as close to the actual text. (Code formatting should not touch the contents of a string, but I can't guarantee that.)
This should round-trip correctly if processing the string line-by-line, as would seem appropriate anyway:
var reader = new StringReader(test);
reader.ReadLine();
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
Console.ReadLine();
Or just read them from a file / resource.

Related

File.Exists(Path) always return false when get 'string (Path)' from text file

I write codes to receive the path of a text file and store it in a string variable that I declare in public.
Then I want to know if the file exists or not by using
System.IO.File.Exists(pathoffile)
But it always returns false even though there is a file.
And then when I try to add the string path directly like this
public string propertyfile = #"C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt"
The function
System.IO.File.Exists(pathoffile)
return true
I already check the receive path(string) that I read from the text file. By cutting off "\n" and "\r" and using trim() too.But it still returns false.
Have I missed something? What difference between these two?. I'm too new to this c#. I'm very bad at this sorry in advance.
Here are my codes
public string pathfromread, partnumber, pathfile, portname, partnofromserial,propertypathfile; //Declare Variables
public string propertyfile = #"C:\Users\PFA Wongsawat\Desktop\Properties.txt";
public string pathoffile ;
public string backuppath ;
public string pdffolderpath ;
private void propertyget()
{
if (File.Exists(propertyfile))
{
StreamReader readpropertyfile = new StreamReader(propertyfile);
string readproperty;
while ((readproperty = readpropertyfile.ReadLine()) != null)
{
string[] propertyfromread = readproperty.Trim().Split('=');
if (propertyfromread.GetValue(0).ToString() == "pathoffile")
{
pathoffile = propertyfromread.GetValue(1).ToString();
pathoffile = pathoffile.Replace("\n", "").Replace("\r", "");
MessageBox.Show(pathoffile, "path file");
}
else if ((propertyfromread.GetValue(0).ToString() == "backuppath"))
{
backuppath = propertyfromread.GetValue(1).ToString();
backuppath = backuppath.Replace("\n", "").Replace("\r", "");
MessageBox.Show(backuppath);
}
else if ((propertyfromread.GetValue(0).ToString() == "pdffolderpath"))
{
pdffolderpath = propertyfromread.GetValue(1).ToString();
pdffolderpath = pdffolderpath.Replace("\n", "").Replace("\r", "");
MessageBox.Show(pdffolderpath);
}
else if ((propertyfromread.GetValue(0).ToString() == "portname"))
{
portname = propertyfromread.GetValue(1).ToString();
portname = portname.Replace("\n", "").Replace("\r", "");
MessageBox.Show(portname);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
propertyget();
dv = dt.DefaultView; //set dv index count to != 0 to prevent error from null input when click on remove button
if (System.IO.File.Exists(pathoffile))//Check if file exist or not
{
}
else
{
try
{
MessageBox.Show("Database Text File Missing. Please Select New File", "Database Text File Missing", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
OpenFileDialog regispath = new OpenFileDialog();
regispath.Title = "Select Database Text File (part_no_and_path_list.txt)";
regispath.Multiselect = false;
regispath.Filter = "Text file (*.txt)|*.txt";
regispath.RestoreDirectory = true;
regispath.ShowDialog();
pathfile = regispath.FileName;
File.Copy(pathfile, pathoffile);
}
catch
{
And this is my property text file
pathoffile=#"C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt"
backuppath=#"C:\Users\PFA Wongsawat\Documents\part_no_and_path_list.txt"
pdffolderpath=#"C:\Users\PFA Wongsawat\Downloads\"
portname=COM3
In this case the result always a messageBox showing "Database Text File Missing. Please Select New File"
Thank you and sorry for my bad English.
You don't put #" and " in the text file, you only put them in the code because that's how the c# compiler knows they're strings (and knows not to interpret slashes as an escape character)
Just make your text file look like:
pathoffile=C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt
I also recommend you use:
Split(new []{'='}, 2)
This will allow you to use = in your path, by making split return a maximum of 2 split values; any = that are legitimately in the path would be preserved
Actually I recommend you use one of the various built in settings mechanisms that c# has; we haven't needed to read and write our own configuration files for about 25 years
If you really do want to continue rolling your own you can reduce your code massively by using a dictionary
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class Settings{
private Dictionary<string,string> _conf = new Dictionary<string,string>();
public string PathOfFile {
get => _conf["pathoffile"];
}
public void ReadConfig(){
File.ReadAllLines("conf.txt").ToDictionary(
x => x.Split(new[]{'='},2)[0],
x => x.Split(new[]{'='},2)[1]
);
}
}
Yep, it's all you need. Every time you want to add another setting, add another property (like public string PathOfFile), add another love to the file and make sure the string in the property matches the line in the file
In other areas, please read up on c# naming conventions; PublicThingsAreNamedLikeThis, _privateLikeThis, localLikeThis, neverlikethis
Thank you I've already solved this problem
By remove "#" and '""' from path in the property text file like this.
pathoffile=C:\Users\PFA Wongsawat\Desktop\part_no_and_path_list.txt
backuppath=C:\Users\PFA Wongsawat\Documents\part_no_and_path_list.txt
pdffolderpath=C:\Users\PFA Wongsawat\Downloads\
portname=COM3
The reason I can't see this because I debug the program by seeing the result in message box and it not match with the real one. Thank you.

how to find word using a file c#

My message box displays hi and his, whenever, my file has the word hello.
My project is supposed to display the messagebox hi only,
and for my code (rtbDisplay.Text = "\n"+"hey";) it override the hello word that
I type.
My project is to create a chatbox. Whenever i type in certain word, it will reply me back with the words that i choose.
File.AppendAllLines(#"C:\\Users\\L31011\\Desktop\\version17\\version17\\FinalProject\\WinRecognize\\bin\\Debug\\Chat\\messages.txt", new[] { rtbType.Text });
StreamReader sr = new StreamReader("C:\\Users\\L31011\\Desktop\\version17\\version17\\FinalProject\\WinRecognize\\bin\\Debug\\Chat\\messages.txt");
rtbDisplay.Text = sr.ReadLine();
//here
string record;
string input = "hello";
string input1 = "goodbye";
try
{
record = sr.ReadToEnd();
while (record != null)
{
if (record.Contains(input))
{
MessageBox.Show("hi");
//rtbDisplay.Text = "\n"+"hey";
}
if (record.Contains(input1))
{
MessageBox.Show("byebye");
}
else
{
MessageBox.Show("his");
}
break;
}
}
finally
{
sr.Close();
}
There are a whole bunch of things that you can do to this. First, the #"string goes here" construct (i.e., with an "at" sign as a preface to the string) means that there is no escaping needed. So you don't need to double up your backslashes (I've been writing in C# since the alpha at the end of 2000, and I didn't realize that #"c:\\some\\file.ext" would work). You can say either "c:\\some\\file.ext" or #"c:\some\file.ext" -- but #"c:\\some\\file.ext" is just weird (and too much typing).
You should read up on using using. It's simpler and clearer than try { } finally { CloseOrDispose() }.
Then there is what #ChetanRanpariya is talking about. Put a breakpoint on the first if statement, when there is "hello" somewhere in the second line to the end. Start single-stepping. Notice that you step into the first message box because of the "hello". Then continue stepping. You don't step into the second message box, because there's no "goodbye". But, there is an else. See what happens next.
By the way, is this really what you want to do? You read the first line, stick it in a text box. Then you read lines 2 through N (all in one go, and into one string) and check to see if "hello" or "goodbye" is on any of them - all in a while loop that will only ever be executed once.

How can you capture the offending line from TextFieldParser when it throws an error?

I'm using the TextFieldParser class to read CSV files. It has two methods for ingesting lines of data: ReadFields() and ReadLine(). As you might imagine the former treats the data as columnar, separated by pre-set delimiters and the latter reads the raw data. I'm using the former, in code like this:
using (TextFieldParser parser = new TextFieldParser(newestFile.FullName))
{
parser.Delimiters = ","
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
try
{
List<string> result = parser.ReadFields().ToList();
// do something
}
catch(MalformedLineException ex)
{
// log error to record line where it happened
}
}
}
The catch for MalformedLineException is there to ensure the thing doesn't fall over if it meets a line that doesn't meet the parsing criteria - it might have additional quotes within a field, for example - it registers this and then moves on to the next line without bringing the whole thing to a halt.
What I'd really like to do in the catch block, though, is log the actual text of the line along with the line number to make it a bit easier to find out what the problem was. But I have no idea how I can get it: ReadFields appears to move on to the next line even when it errors, and if I call ReadLine in the catch block it also moves on to the next line, meaning lines get skipped. It does not appear to be part of the exception thrown, or available via the object when ReadFields fails.
Is there a way to use the TextFieldParser to capture this data?
I didn't actually intend to answer my own question, but this turned out to be very easy: there are other methods on the object to do just this: ErrorLine and ErrorLineNumber.
using (TextFieldParser parser = new TextFieldParser(newestFile.FullName))
{
parser.Delimiters = ","
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
try
{
List<string> result = parser.ReadFields().ToList();
// do something
}
catch(MalformedLineException ex)
{
int errorLine = parser.ErrorLineNumber;
string originalData = parser.ErrorLine;
// log them
}
}
}

I need to return a line of string to the user from a text file in C#

public class QuoteGenerator
{
public static randomQuote()
{
string t = "Quotes.txt";
List<string> Quotes = new List<string>();
using (StreamReader quoteReader = new StreamReader(t))
{
string line = "";
while ((line = quoteReader.ReadLine()) != null)
{
Quotes.Add(line);
}
}
string[] response = Quotes.ToArray();
string[] shuffle = Classes.RandomStringArrayTool.RandomizeStrings(response);
return (shuffle[0]);
}
}
Here's what's working and I thought my StreamReader code above would work the same:
public string randomQuote()
{
string[] response = new string[] {"The fortune you seek, is in another bot"
, "Someone has Googled you recently"
, "This fortune no good. Try another"
, "404 fortune not found"};
string[] shuffle = Classes.RandomStringArrayTool.RandomizeStrings(response);
return shuffle[0];
}
I need to return the first line of quote from the StreamReader Method, how come the code I put together doesn't seem to work? I've thought about hard-coding the quotes but maybe it's a good idea to save them in a text file. I guess I don't understand how using StreamReader work. Can anyone please explain, I've only been coding since July. Thank you!
Assuming your Quotes.txt file is in the bin directory the StreamReader code works fine. The only thing obvious is that you are not specifying a return type for the randomQuote method.
public static string randomQuote()

String appears differently depending on use scenario

Getting some odd behavior with JSON data which is being loaded into an observablecollection.
Here's an example of the JSON import, and how my folder path is shown.
{
"projectNumber":"16000",
"projectName":"Sample Project",
"Directory":"#\"C:\\Users\"", }
So far I've been able to use the data as expected after loading into my observablecollection. For example, the messagebox shows (selectedfolder) in the messagebox as intended: #"C:\Users"
This is the path I want my treeview to use. Oddly, it's not using that but instead uses the original path format from my JSON import instead ("#\"C:\Users\"") and throws an "Illegal characters in path" error.
private void ListDirectory(TreeView treeView, string path)
{
treeView.Items.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Items.Add(CreateDirectoryNode(rootDirectoryInfo));
}
private static TreeViewItem CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeViewItem { Header = directoryInfo.Name };
foreach (var directory in directoryInfo.GetDirectories())
directoryNode.Items.Add(CreateDirectoryNode(directory));
foreach (var file in directoryInfo.GetFiles())
directoryNode.Items.Add(new TreeViewItem { Header = file.Name });
return directoryNode;
}
private void button_Click(object sender, RoutedEventArgs e)
{
Project selectedProject = comboBox.SelectedItem as Project;
selectedfolder = selectedProject.Directory.ToString();
MessageBox.Show(selectedfolder);
if (selectedProject != null)
{
this.ListDirectory(treeView, selectedfolder);
}
Anybody see what I'm missing here, and why the same string would appear differently depending on how it's being used?
The #"" string literal is used to help write code that has strings with backslashes in it. This bit of code, for instance, contains a reference to a valid path, and the #"" bit just tells the C# compiler to treat backslashes differently than normal C-style strings:
string example1 = #"C:\Users";
Debug.WriteLine(example1); // Outputs C:\Users
// This works
var temp1 = new DirectoryInfo(example1);
Once you actually embed the #"" bit in a string, you end up with a string that contains # and " characters in it, which isn't going to be a valid path on Windows.
string example2 = "#\"C:\\Users\"";
Debug.WriteLine(example2); // Outputs #"C:\Users"
// This throws an exception
var temp2 = new DirectoryInfo(example2);
In other words: Using #"" is fine for C# code, but for a JSON object, you'll need to change your JSON text to be something like this, using \ to escape characters, so it's a valid path after the JSON deserializer finishes parsing the string:
{
"projectNumber":"16000",
"projectName":"Sample Project",
"Directory":"C:\\Users",
}
That was clearly the answer. Thanks so much, Anon! What was throwing me off was how the string showed in a messagebox exactly how I would use it in a path reference. Newbie mistake!

Categories

Resources