Adding text to a file is displayed in one long line - c#

I am having an issue where when I write text to a second file, it display fine in wordpad where it includes the linebreaks, but in notepad all the text for copyText and richTextBox1.Text appear in one really long line.
How can I fix this? If somebody can include a code snippet with my code then it will be much appreciated as I can see what you have done and changed and I can keep it for reference for futr use.
My code is below where I take text from a text file (Testfile.txt) and insert it into richTextBox1, then when I click on button, text is copied to richText Box2 and is written in second file (_Parsed.txt).
I did a message box on text line and it displays text all without line break. I'm not sure if that is issue but I do need help as deadline is tomorrow and this is only thing I need to sort out and I'm done.
string Chosen_File = "C:\\_Testfile.txt";
string Second_File = "C:\\_Parsed.txt";
string wholeText = "";
private void mnuOpen_Click(object sender, EventArgs e) {
//Add data from text file to rich text box
richTextBox1.LoadFile(Chosen_File, RichTextBoxStreamType.PlainText);
//Read lines of text in text file
string textLine = "";
StreamReader txtReader;
txtReader = new StreamReader(Chosen_File);
do {
textLine = textLine + txtReader.ReadLine() + " ";
}
//Read line until there is no more characters
while (txtReader.Peek() != -1);
richTextBox1.Text = textLine;
txtReader.Close();
}
}
private void Write(string file, string text) {
//Check to see if _Parsed File exists
//Write to _Parsed text file
using(StreamWriter objWriter = new StreamWriter(file)) {
objWriter.Write(text);
objWriter.Close();
}
}
private void newSummaryMethod(string copyText) {
//Write into richTextBox2 all relevant text
copyText = richTextBox1.Text;
wholeText = richTextBox1.Text + copyText
Write(Second_File, wholeText);
}
private void btn1_Click(object sender, EventArgs e) {
newSummaryMethod(copyText);
}

The problem is probably with the line breaks in your text file(s).
TextBoxes expect \r\n sequence as an indication of the end-of-line, and your text files may contain only the \n.
Try to make this change to your code:
do {
textLine = textLine + txtReader.ReadLine() + "\r\n";
}
//Read line until there is no more characters
while (txtReader.Peek() != -1);

The problem is that you are never adding a new line to the file in your code. you are using objWriter.Write(text); which does not generate a new line.
you can use objWriter.WriteLine(text); instead and it will automatically add new line character at the end.
I think the difference in viewing the file is because the "word wrap" option is turned on in "wordpad" and it causes to break a long line into multiple line.

Related

Combobox loading text with invisible linefeed (\r) or newline (\n)

I'm using c#, visual studio 2017, winforms and
I'm having a problem with a combobox which is loading some text from a text file and when I select another line of text from the combobox, a linefeed (\r) is added there, and it looks like it's somewhat invisible or better saying, it looks like a newline (\n).
This is the combobox in question and the invisible linefeed (\r).
https://i.stack.imgur.com/Xhymg.png
When I debug the application I can see \r added after that line of text.
https://i.stack.imgur.com/km4F3.png
I've tried to use Encoding.Unicode when saving the text, but to no avail.
//This is how I save text to a file
private void SaveVarNameToFile()
{
using (var writer = File.AppendText("savedVarName.txt"))
{
writer.Write(comboBox1.Text, Encoding.Unicode);
}
}
//This is how I load the text to combobox
private void LoadStrTextFromFile(string fileName, ComboBox cb)
{
if (!File.Exists(fileName))
return;
using (StreamReader reader = new StreamReader(fileName))
{
string x = reader.ReadToEnd();
string[] y = x.Split('\n');
foreach (string s in y)
{
cb.Items.Add(s);
}
reader.Close();
}
}
Contents of the text file:
BOOST_ROOT
NUMBER_OF_PROCESSORS
OS
PROCESSOR_LEVEL
I'm having a hard time figuring out how to remove that pesky little thing. Perhaps there's an easy fix.
If someone can help me find a way or remove it or modify the code so it won't load the \r, I would be very grateful. Thanks.
Windows uses \r\n to mark the end of a line of text. *NIX and Macs use different markers. You can see how different systems handle this here.
Instead of handling the splitting of lines manually, I recommend using built-in functionality for doing this (i.e. File.ReadLines()):
private void LoadStrTextFromFile(string fileName, ComboBox cb)
{
if (!File.Exists(fileName))
return;
foreach (string line in File.ReadLines(fileName))
cb.Items.Add(line);
}
My approach
// remember to use double back slash on the path
string[] text = System.IO.File.ReadAllLines("C:\\test.txt").Where(line => !string.IsNullOrWhiteSpace(line)).Distinct().ToArray(); // read the file into a string array with removing the duplicates and empty lines
comboBox1.Items.AddRange(text); // finally fill in the combobox with the array

Multiple lines not reading into one list item

For some reason when I read in clipboard data and write it to a file, read that file in and set it to a list after delineating it with ¢ it loads up my listbox just fine on the first load as in when my form first loads up. However I have the following trigger on a button click, it is for some reason splitting up multiple line sections into separate list items, which is not what I want and not what the same code does when the form first loads. It's a little frustrating as it's writing to the text file and everything the same way.
private void button2_Click_1(object sender, EventArgs e)
{
// until next comment this is the same as what I have run at the start of the
// program, it loads up multiple lines into one list item as it should
string checkForDupe = File.ReadAllText(#"C:\temp\testfile.txt");
string checkResponses = File.ReadAllText(#"C:\temp\testfile2.txt");
if (Clipboard.ContainsText() && !checkForDupe.Contains(Clipboard.GetText()))
{
if (!checkResponses.Contains(Clipboard.GetText()))
{
var text = "\n" + Clipboard.GetText() + "¢";
File.AppendAllText(#"C:\temp\testfile.txt", text);
}
}
//The following has no affect on the issue stated in my question I have tried with out it.
string[] responseTags2 = File.ReadAllLines(#"C:\temp\testfile.txt");
List<string> _responseTags2 = new List<string>(responseTags2);
var count = _responseTags2.Count;
// Perform a reverse tracking.
for (var i = count - 1; i > -1; i--)
{
if (_responseTags2[i] == string.Empty) _responseTags2.RemoveAt(i);
}
// Keep only the unique list items.
_responseTags2 = _responseTags2.Distinct().ToList();
listBox1.BeginUpdate();
listBox1.DataSource = _responseTags2;
listBox1.EndUpdate();
}
input example:
"This is multiple lines in
a text file that is for testing
this application"
right output example (what I get when the same code is running at the start of the program before the form is loaded):
"This is multiple lines in
a text file that is for testing
this application" ,
"This is ANOTHER multiple lines in
a text file that is for testing
this application" ,
"This is a single line"
WRONG output (what I get when I run off the button click that eventual updates the UI):
"This is multiple lines in",
"a text file that is for testing",
"this application"
You are getting multiple lines in your listbox because you are not breaking the text by ¢ but just reading them into lines. This is your code:
string[] responseTags2 = File.ReadAllLines(#"C:\temp\testfile.txt");
Do this instead. Read all the text:
var contents = File.ReadAllText(#"C:\temp\testfile.txt");
Now split them using the character ¢:
var lines = s.Split('¢');
Here is the final linq to remove any empties and return distinct items:
var lines = s.Split('¢')
.Where(item => item != string.Empty)
.Distinct()
.ToList();
Then set lines to be the datasource:
listBox1.BeginUpdate();
listBox1.DataSource = lines;
listBox1.EndUpdate();
This code works fine for me, but I think it's basically what you're doing, only slightly cleaned up (and I didn't use the second file since you're not using it in the example).
My suggestion would be to create a single method that does this operation, and then call that method from wherever you need it. This way you will ensure that you're doing the exact same thing in both (all) places.
UPDATE
I updated the method to save the clipboard text as-is, plus adding a ¢ character to the end, when saving to the file. Then, when reading the file the second time, first join all the lines with a space character, then split on the ¢ character, and use that list for your data source.
private const string DefaultSaveFile = #"C:\temp\testfile.txt";
private void CopyUniqueClipboardTextToFile(string filePath = null,
bool updateListbox = true)
{
// Use global default file if nothing was passed
if (filePath == null) filePath = DefaultSaveFile;
// Ensure our files exist
if (!File.Exists(filePath)) File.CreateText(filePath).Close();
string fileContents = File.ReadAllText(filePath);
string clipboardText = Clipboard.GetText();
// Update the file with any new clipboard text
if (Clipboard.ContainsText() && !fileContents.Contains(clipboardText))
{
// Save the lines to our file, with a '¢' character at the end
File.AppendAllText(filePath, $"{Environment.NewLine}{clipboardText}¢");
}
// Re-read the new file into a single string
string entireFileAsOneLine = string.Join(" ",
File.ReadAllLines(filePath).Distinct().ToList());
// Now split that string on the '¢' character
string[] listItems = entireFileAsOneLine.Split('¢');
// Update listbox if necessary
if (updateListbox)
{
listBox1.BeginUpdate();
listBox1.DataSource = listItems;
listBox1.EndUpdate();
}
}
private void button2_Click(object sender, EventArgs e)
{
CopyUniqueClipboardTextToFile();
}
What I ended up doing is the following;
string responseTags2 = checkForDupe.Replace('\n', '╜');
I replaced new lines with a rarely used character, then split by ¢ to fill the list.
To replace the special character so that it would be formatted correctly again I just replaced it when setting the clipboard text with the \n again.

While loop isn't detecting first line of text file

I have a program that loads text files to populate two separate list boxes in the form. It's supposed to read every line, and add each line to a single listbox. The first line of the text file is being ignored for some reason, and I'm not sure why.
This is what each line of the text file is:
cd Armor 1 True+
bg Tool 2 False+
o Weapon 3 False-
xz Consumable 1 True-
I believe my while loop is the issue, but I'm not sure what I'm doing wrong with it. I need the program to loop through more than one line. When I ran the code without using a loop, the first line of the text file was added to the appropriate list box with no issues.
The code below is attached to the load button within my form.
private void loadToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog openTextFile = new OpenFileDialog();
openTextFile.Filter = "Text Files (*.txt) | *.txt";
string listItemString;
string[] listItem;
if (openTextFile.ShowDialog() == DialogResult.OK)
{
using (StreamReader openStream = new StreamReader(openTextFile.OpenFile()))
{
listItemString = openStream.ReadLine();
listItem = listItemString.Split(' ');
while ((listItemString = openStream.ReadLine()) != null)
{
if (listItemString.EndsWith("+"))
{
listItemString = listItemString.Replace("+", "");
cart.Items.Add(listItemString);
}
else if (listItemString.EndsWith("-"))
{
listItemString = listItemString.Replace("-", "");
delivery.Items.Add(listItemString);
}
}
}
}
}
You are reading first line before while loop in the line of code listItemString = openStream.ReadLine();. Then you are overridden this value in the first loop iteration when calls while ((listItemString = openStream.ReadLine()) != null) first time.
Just delete 2 lines of code befoer yout loop:
listItemString = openStream.ReadLine();
listItem = listItemString.Split(' ');

Multi-line textbox shows mult-line string as One-Line

I am making a program where you enter an item's name and it's description. Then you add it to a listbox and after you are done you can save all the items to a 'txt' file. (Using StreamWriter). This program also has an edit button that allows you to edit the description in the listbox by removing it first from the listbox and then showing it back in the textbox (, so you can edit it)
If the description is multi-line, it will successfuly show it multi-line when I select it in the listbox and click the edit button that will show it back in the textbox. BUT if I save all the items in the listbox to a file first. And then open up the file again so it load the items back into the listbox. And then clicking the edit button...
The multi-line description will show as a one-line description in the textbox.
I am not sure why - but I've also made a label that will show the exact string that the textbox is suppose to show and the label is showing it multi-lined while textbox isn't!
The string is definitely multi-line but the multi-line textbox is showing it one-line after loading the items back into the listbox using StreamReader.
Example of the multi-line string: (named "theString1")
This is line 1
This is line 2
Using the following code: TextBox1.Text = theString1; this appears in the text box:
This is line1This is line2
But if I use the same code with a label. It will show it correctly.
If someone can explain to me why this is happening I will be more than happy. I just need an explanation.
Thanks in advance.
---[More info]---
Just so you know. I came up with this code myself so it is probably set-up all wrong.
I will be happy if you tell me a better way to do this.
I am using a list to store the description text + the item name. I seperated these two using '`' .And splited the string (see code).
This is the code that happens when you click the edit button. It removes the item from
the listbox and shows it in the textbox so you can edit it and add to listbox again:
int index = listBox.SelectedIndex;
itemName.Text = listBox.SelectedItem.ToString();
var descVar = descList.ElementAt(index).Split('`');
string theString1 = descVar[1];
TextBox1.Text = theString1;
This is how it saves it to a file:
FileDialog save = new SaveFileDialog();
save.Title = "Save information...";
save.DefaultExt = "Text File|*.txt";
save.Filter = "Text File|*.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(save.FileName);
foreach (string s in listBox.Items) //This writes the names of item names.
{
sw.WriteLine(s);
}
sw.WriteLine("`1`"); //I use this to seperate the item names from description.
foreach (string s in descList) //This writes the descriptions that are stored in a list named "descList".
{
sw.WriteLine(s);
sw.WriteLine("``"); //I use this to seperate descriptions from each other because they are multi-line.
}
sw.WriteLine("`2`"); //Just something so I know where it ends. :D
sw.Close();
}
else
{
}
And this is how it loads: (This can definitely be better!)
FileDialog load = new OpenFileDialog();
load.Title = "Load information...";
load.DefaultExt = "Text File|*.txt";
load.Filter = "Text File|*.txt";
if (load.ShowDialog() == DialogResult.OK)
{
List<string> loadDesc = new List<string>(); //Don't ask you will see why
descList.Clear();
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
{
int index = 0;
listBox.Items.RemoveAt(index);
descList.Clear();
itemName.Text = "";
}
StreamReader rw = new StreamReader(load.FileName);
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
for (; true; )
{
string read = rw.ReadLine();
if (read == "`2`")
{
break;
}
else
{
loadDesc.Clear();
loadDesc.Add(read);
for (; true; ) //Please tell me if this can be done differently.
{
string read2 = rw.ReadLine();
if (read2 != "``") //This will keep reading the whole description until it reaches the separator.
{
loadDesc.Add(read2); //Adds each line into the list I created.
}
else
{
break;
}
}
string oneBigString = string.Join("\n", loadDesc); //This basically converts all strings in a list into one string.
descList.Add(oneBigString); //And this finally add the string to the main list from where it then loads.
}
}
}
else
{
}
I believe that is it.
If there is anything else you need - tell me.
string oneBigString = string.Join("\n", loadDesc); is where the issue is.
Use Environment.NewLine instead of \n
I'm also just going to go over a couple of things that could be improved with your code (there are a lot, but I just want to cover a couple).
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
You don't need to iterate over every element in the listbox to remove it. You can just do listBox.clear()
Also, using break to get out of loops is generally bad practice. This should be written as...
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
this
string read = rw.ReadLine()
while(read != "`1`")
{
listBox.Items.Add(read);
read = rw.ReadLine()
}
but theres more, what if 1 is never found in the file? It would crash your program, so you also need to check if there is more data to be read...
string read = rw.ReadLine()
while(read != "`1`" && !sw.EndOfStream) // Make sure you're not at the end of the file
{
listBox.Items.Add(read);
read = rw.ReadLine()
}

How to append \line into RTF using RichTextBox control

When using the Microsoft RichTextBox control it is possible to add new lines like this...
richtextbox.AppendText(System.Environment.NewLine); // appends \r\n
However, if you now view the generated rtf the \r\n characters are converted to \par not \line
How do I insert a \line control code into the generated RTF?
What does't work:
Token Replacement
Hacks like inserting a token at the end of the string and then replacing it after the fact, so something like this:
string text = "my text";
text = text.Replace("||" "|"); // replace any '|' chars with a double '||' so they aren't confused in the output.
text = text.Replace("\r\n", "_|0|_"); // replace \r\n with a placeholder of |0|
richtextbox.AppendText(text);
string rtf = richtextbox.Rtf;
rtf.Replace("_|0|_", "\\line"); // replace placeholder with \line
rtf.Replace("||", "|"); // set back any || chars to |
This almost worked, it breaks down if you have to support right to left text as the right to left control sequence always ends up in the middle of the placeholder.
Sending Key Messages
public void AppendNewLine()
{
Keys[] keys = new Keys[] {Keys.Shift, Keys.Return};
SendKeys(keys);
}
private void SendKeys(Keys[] keys)
{
foreach(Keys key in keys)
{
SendKeyDown(key);
}
}
private void SendKeyDown(Keys key)
{
user32.SendMessage(this.Handle, Messages.WM_KEYDOWN, (int)key, 0);
}
private void SendKeyUp(Keys key)
{
user32.SendMessage(this.Handle, Messages.WM_KEYUP, (int)key, 0);
}
This also ends up being converted to a \par
Is there a way to post a messaged directly to the msftedit control to insert a control character?
I am totally stumped, any ideas guys? Thanks for your help!
Adding a Unicode "Line Separator" (U+2028) does work as far as my testing showed:
private void Form_Load(object sender, EventArgs e)
{
richText.AppendText("Hello, World!\u2028");
richText.AppendText("Hello, World!\u2028");
string rtf = richText.Rtf;
richText.AppendText(rtf);
}
When I run the program, I get:
Hello, World!
Hello, World!
{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
{\colortbl ;\red255\green255\blue255;}
\viewkind4\uc1\pard\cf1\f0\fs17 Hello, World!\line Hello, World!\line\par
}
It did add \line instead of \par.
Since you want to use a different RTF code, I think you may need to forget about the simplistic AppendText() method and manipulate the .Rtf property of your RichTextBox directly instead. Here is a sample (tested) to demonstrate:
RichTextBox rtb = new RichTextBox();
//this just gets the textbox to populate its Rtf property... may not be necessary in typical usage
rtb.AppendText("blah");
rtb.Clear();
string rtf = rtb.Rtf;
//exclude the final } and anything after it so we can use Append instead of Insert
StringBuilder richText = new StringBuilder(rtf, 0, rtf.LastIndexOf('}'), rtf.Length /* this capacity should be selected for the specific application */);
for (int i = 0; i < 5; i++)
{
string lineText = "example text" + i;
richText.Append(lineText);
//add a \line and CRLF to separate this line of text from the next one
richText.AppendLine(#"\line");
}
//Add back the final } and newline
richText.AppendLine("}");
System.Diagnostics.Debug.WriteLine("Original RTF data:");
System.Diagnostics.Debug.WriteLine(rtf);
System.Diagnostics.Debug.WriteLine("New Data:");
System.Diagnostics.Debug.WriteLine(richText.ToString());
//Write the RTF data back into the RichTextBox.
//WARNING - .NET will reformat the data to its liking at this point, removing
//any unused colors from the color table and simplifying/standardizing the RTF.
rtb.Rtf = richText.ToString();
//Print out the resulting Rtf data after .NET (potentially) reformats it
System.Diagnostics.Debug.WriteLine("Resulting Data:");
System.Diagnostics.Debug.WriteLine(rtb.Rtf);
Output:
Original RTF data:
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}
\viewkind4\uc1\pard\f0\fs17\par
}
New RTF Data:
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}
\viewkind4\uc1\pard\f0\fs17\par
example text0\line
example text1\line
example text2\line
example text3\line
example text4\line
}
Resulting RTF Data:
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}
\viewkind4\uc1\pard\f0\fs17\par
example text0\line example text1\line example text2\line example text3\line example text4\par
}
if you are using paragraphs to write to richtextbox you can use the LineBreak() same code shown below
Paragraph myParagraph = new Paragraph();
FlowDocument myFlowDocument = new FlowDocument();
// Add some Bold text to the paragraph
myParagraph.Inlines.Add(new Bold(new Run(#"Test Description:")));
myParagraph.Inlines.Add(new LineBreak()); // to add a new line use LineBreak()
myParagraph.Inlines.Add(new Run("my text"));
myFlowDocument.Blocks.Add(myParagraph);
myrichtextboxcontrolid.Document = myFlowDocument;
Hope this helps!

Categories