wrong format when saving to file - c#

I am trying to save a String Builder to a file but it doesn't make new line.
the output should look like
output without new line
class Program
{
static public void justify(List<string> words, int width)
{
//some code to build the arrays
int ii = 0, jj;
StringBuilder builder = new StringBuilder();
do
{
jj = result[ii];
for(int k = ii; k < jj; k++)
{
builder.Append(words[k] + " ");
}
builder.Append("\n");
ii = jj;
}
while(jj < words.Count);
Console.WriteLine(builder.ToString());
StreamWriter file = new StreamWriter("output.txt");
file.Write(builder.ToString());
file.Close();
}
static void Main(string[] args)
{
string file_extention, file1;
file1 = Console.ReadLine();
file_extention = "C:\\Users\\sayed\\Desktop\\" + file1 + ".txt";
string text = System.IO.File.ReadAllText(#file_extention);
result = text.Split(' ').ToList();
justify(result, 10);
}
}

That's because the you should use \r\n for new lines in Windows. \n is Unix. You should use
builder.AppendLine();
which does this automatically. More precisely, AppendLine() appends a \r\n on non-Unix platforms and a string \n on Unix platforms.
Note that your file does indeed contain the \n which some editors do interpret as line breaks even on Windows. Notepad, for instance, does not.

Replace
builder.Append("\n");
with
builder.Append(Environment.NewLine);
Then open your file with notepad++ instead of window's default text editor.
I believe your \n characters are being ignored by notepad and so they aren't rendering. On Windows machines, it expects a \r\n to render a newline and Environment.NewLine will make sure you get the right one.

Related

Why is StreamWriter writing crosses and Chinese characters?

I have a little script that converts a pixel art image into a string, using 'X' for opaque pixels, ' ' for transparent pixels, and '\n' after each row. I want to then write this string to a text file, which seems simple enough.
[SerializeField] Sprite sprite;
[SerializeField] string newFileName;
private string textFilesFolderLocation = //A location on my computer.
private string fileExtension = ".txt";
public void CreateTextDocument() {
string ascii = CreateAscii();
string path = textFilesFolderLocation + #"\" + newFileName + fileExtension;
if (File.Exists(path)) {
File.Delete(path);
}
using (StreamWriter streamWriter = new StreamWriter(path)) {
streamWriter.Write(ascii);
}
}
private string CreateAscii() {
StringBuilder stringBuilder = new StringBuilder();
Texture2D pixels = sprite.texture;
for (int y = pixels.height - 1; y >= 0; y--) {
for (int x = 0; x < pixels.width; x++) {
Color pixel = pixels.GetPixel(x, y);
if (pixel.a > 0) {
stringBuilder.Append("x");
}
else {
stringBuilder.Append(" ");
}
}
stringBuilder.Append('\n');
}
return stringBuilder.ToString();
}
This works as expected with ~90% of my images, but a few are writing some seemingly bizarre characters to their text files! Variations of the following:
"...††††††††††††††††††††††††††††††††††††††††††††††††††
††††††††††††††††††††††††††††††††††††††††††††††††砠†
⁸††††††††砠†硸††††††††††††††††††††††††††††††砠†††††
††††砠†††††砠砠††††††††††††††††††††††††††††⁸††††††††
††††††††††††..." (the full text is around 50,000 characters long)
After investigating, I can confirm that CreateAscii() is working correctly. Printing the string to the console reveals that it is comprised of 'x' and ' ', as expected.
I have found that attempting to write simple messages like "Hello World" works as expected, and that writing a small piece of the ascii string also works. But with the few problematic images, trying to write the whole string results in "...†砠†硸†††...".
Even if I try to write small pieces sequentially like
for (int i = 0; i < ascii.Length; i++) {
using (StreamWriter streamWriter = new StreamWriter(path, append: true)) {
streamWriter.Write(ascii[i]);
}
}
I still get exclusively "...†砠†硸†††..." in my text file.
Does anybody know what might be going on?
Thanks to the helpful replies in the comments, I learned that Notepad was having trouble displaying my files correctly. Opening the .txt files with a different viewer enabled me to see the text properly.
I still don't know what the root problem was, but this is good enough for me!

Display formatted text on console using padding

I´m planning to write a description of the parameters of my console-app in a formated way similar to the follwoing:
The following options are possible:
myOption: Text do describe the option, but that should be splitted
to several lines if too big. Text should automatically
align by a fixed offset.
I already got a method to split the text at the right positions (assuming we do not care if we split in the midlle of any word, we would cimplicate things only if we´d care if we actually split at word-boundaries). However I am stuck on aligning the options explanation.
This is the code so far:
public void DisplayHelpEx()
{
var offset = this._options.Max(x => x.ParameterName.Length) + 6;
Console.WriteLine("The following options are possible:");
foreach (var option in this._corrections)
{
Console.Write((option.ParameterName + ": ").PadLeft(offset));
WriteOffset(offset, option.Explanation);
}
}
public void WriteOffset(int offset, string text)
{
var numChars = TOTAL_NUMBER_CHARS_PER_LINE - offset;
string line;
while ((line = new String(text.Take(numChars).ToArray())).Any())
{
var s = line.PadLeft(numChars);
Console.Write(s);
Console.WriteLine();
text= new String(text.Skip(numChars).ToArray());
}
}
I have tried many combinations of .PadLeft and .PadRight but can´t get it to work.
With the approach above I get the following output:
The following options are possible:
myOption: Text do describe the option, but that should be splitted
to several lines if too big. Text should automatically
align by a fixed offset.
PadLeft takes the text and adds some spaces left or right so that the full text will have a defined width, see https://msdn.microsoft.com/en-us/library/system.string.padleft(v=vs.110).aspx .
However, in your case, you don't want to have the whole text to have a fixed width (especially not if you in future want to split nicely at word boundaries), but rather the offset at the beginning. So why don't you just add the offset spaces at the beginning of each line, like so?
private const string optionParameterName = "myOption";
private const string optionText =
"Text do describe the option, but that should be splitted to several lines if too big.Text should automatically align by a fixed offset.";
private const int TOTAL_NUMBER_CHARS_PER_LINE = 60;
public void DisplayHelpEx()
{
var offset = optionParameterName.Length + 6;
Console.WriteLine("The following options are possible:");
WriteOffset(offset, optionParameterName + ": ", optionText);
}
public void WriteOffset(int offset, string label, string text)
{
var numChars = TOTAL_NUMBER_CHARS_PER_LINE - offset;
string offsetString = new string(' ', offset);
string line;
bool firstLine = true;
while ((line = new String(text.Take(numChars).ToArray())).Any())
{
if (firstLine)
{
Console.Write(label.PadRight(offset));
}
else
{
Console.Write(offsetString);
}
firstLine = false;
Console.Write(line);
Console.WriteLine();
text = new String(text.Skip(numChars).ToArray());
}
}
// output:
// The following options are possible:
// myOption: Text do describe the option, but that should b
// e splitted to several lines if too big.Text sh
// ould automatically align by a fixed offset.
Note that I used label.PadRight(offset) in the first line to make sure that the string with the label is padded to the correct length -- here the padding is useful because it allows us to make the label string have exactly the same width as the other offsets.
in WriteOffset method you do weird things with text and it is hard to follow its modifications
test with a fiddle modified program
public class Program
{
static int TOTAL_NUMBER_CHARS_PER_LINE = 64;
public static void Main()
{
DisplayHelpEx();
}
// i only set test params here
public static void DisplayHelpEx()
{
string ParameterName = "myOption";
string Explanation = "Text do describe the option, but that should be splitted to several lines if too big. Text should automatically align by a fixed offset";
int offset = ParameterName.Length + 6;
Console.WriteLine("The following options are possible:");
// print caption
Console.Write((ParameterName + ": ").PadLeft(offset));
// print help
WriteOffset(offset, TOTAL_NUMBER_CHARS_PER_LINE - offset, Explanation);
}
private static void WriteOffset(int offset, int width, string text)
{
string pad = new String(' ', offset);
int i = 0;
while (i < text.Length)
{
// print text by 1 symbol
Console.Write(text[i]);
i++;
if (i%width == 0)
{
// when line end reached, go to next
Console.WriteLine();
// make offset for new line
Console.Write(pad);
}
}
}
}

Make Console.WriteLine() wrap words instead of letters

Using Console.WriteLine(), this it output:
I want it to look like this automatically, instead of manually putting in \n wherever needed:
Is this possible? If so, how?
Here is a solution that will work with tabs, newlines, and other whitespace.
using System;
using System.Collections.Generic;
/// <summary>
/// Writes the specified data, followed by the current line terminator, to the standard output stream, while wrapping lines that would otherwise break words.
/// </summary>
/// <param name="paragraph">The value to write.</param>
/// <param name="tabSize">The value that indicates the column width of tab characters.</param>
public static void WriteLineWordWrap(string paragraph, int tabSize = 8)
{
string[] lines = paragraph
.Replace("\t", new String(' ', tabSize))
.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; i++) {
string process = lines[i];
List<String> wrapped = new List<string>();
while (process.Length > Console.WindowWidth) {
int wrapAt = process.LastIndexOf(' ', Math.Min(Console.WindowWidth - 1, process.Length));
if (wrapAt <= 0) break;
wrapped.Add(process.Substring(0, wrapAt));
process = process.Remove(0, wrapAt + 1);
}
foreach (string wrap in wrapped) {
Console.WriteLine(wrap);
}
Console.WriteLine(process);
}
}
This will take a string and return a list of strings each no longer than 80 characters):
var words = text.Split(' ');
var lines = words.Skip(1).Aggregate(words.Take(1).ToList(), (l, w) =>
{
if (l.Last().Length + w.Length >= 80)
l.Add(w);
else
l[l.Count - 1] += " " + w;
return l;
});
Starting with this text:
var text = "Hundreds of South Australians will come out to cosplay when Oz Comic Con hits town this weekend with guest stars including the actor who played Freddy Krueger (A Nightmare on Elm Street) and others from shows such as Game of Thrones and Buffy the Vampire Slayer.";
I get this result:
Hundreds of South Australians will come out to cosplay when Oz Comic Con hits
town this weekend with guest stars including the actor who played Freddy Krueger
(A Nightmare on Elm Street) and others from shows such as Game of Thrones and
Buffy the Vampire Slayer.
Coded in a couple of minutes, it will actually break with words that have more than 80 characters and doesn't take into consideration the Console.WindowWidth
private static void EpicWriteLine(String text)
{
String[] words = text.Split(' ');
StringBuilder buffer = new StringBuilder();
foreach (String word in words)
{
buffer.Append(word);
if (buffer.Length >= 80)
{
String line = buffer.ToString().Substring(0, buffer.Length - word.Length);
Console.WriteLine(line);
buffer.Clear();
buffer.Append(word);
}
buffer.Append(" ");
}
Console.WriteLine(buffer.ToString());
}
It's also not very optimized on both CPU and Memory. I wouldn't use this in any serious context.
This should work, although it can probably be shortened some more:
public static void WordWrap(string paragraph)
{
paragraph = new Regex(#" {2,}").Replace(paragraph.Trim(), #" ");
var left = Console.CursorLeft; var top = Console.CursorTop; var lines = new List<string>();
for (var i = 0; paragraph.Length > 0; i++)
{
lines.Add(paragraph.Substring(0, Math.Min(Console.WindowWidth, paragraph.Length)));
var length = lines[i].LastIndexOf(" ", StringComparison.Ordinal);
if (length > 0) lines[i] = lines[i].Remove(length);
paragraph = paragraph.Substring(Math.Min(lines[i].Length + 1, paragraph.Length));
Console.SetCursorPosition(left, top + i); Console.WriteLine(lines[i]);
}
}
It may be hard to understand, so basically what this does:
Trim() removes spaces at the start and the end.
The Regex() replaces multiple spaces with one space.
The for loop takes the first (Console.WindowWidth - 1) characters from the paragraph and sets it as a new line.
The `LastIndexOf()1 tries to find the last space in the line. If there isn't one, it leaves the line as it is.
This line is removed from the paragraph, and the loop repeats.
Note: The regex was taken from here.
Note 2: I don't think it replaces tabs.
You can use CsConsoleFormat† to write strings to console with word wrap. It's actually the default text wrapping mode (but it can be changed to character wrap or no wrap).
var doc = new Document().AddChildren(
"2. I have bugtested this quite a bit however if something "
+ "goes wrong and the program crashes just restart it."
);
ConsoleRenderer.RenderDocument(doc);
You can also have an actual list with margin for numbers:
var docList = new Document().AddChildren(
new List().AddChildren(
new Div("I have not bugtested this enough so if something "
+ "goes wrong and the program crashes good luck with it."),
new Div("I have bugtested this quite a bit however if something "
+ "goes wrong and the program crashes just restart it.")
)
);
ConsoleRenderer.RenderDocument(docList);
Here's what it looks like:
† CsConsoleFormat was developed by me.
If you have a word (like a path) greater than screen width, you also needs word wrap.
using System;
using System.Text;
namespace Colorify.Terminal
{
public static class Wrapper
{
static int _screenWidth { get; set; }
public static void Text(string text)
{
StringBuilder line = new StringBuilder();
string[] words = text.Split(' ');
_screenWidth = (Console.WindowWidth - 3);
foreach (var item in words)
{
Line(ref line, item);
Item(ref line, item);
}
if (!String.IsNullOrEmpty(line.ToString().Trim()))
{
Out.WriteLine($"{line.ToString().TrimEnd()}");
}
}
static void Line(ref StringBuilder line, string item)
{
if (
((line.Length + item.Length) >= _screenWidth) ||
(line.ToString().Contains(Environment.NewLine))
)
{
Out.WriteLine($"{line.ToString().TrimEnd()}");
line.Clear();
}
}
static void Item(ref StringBuilder line, string item)
{
if (item.Length >= _screenWidth)
{
if (line.Length > 0)
{
Out.WriteLine($" {line.ToString().TrimEnd()}");
line.Clear();
}
int chunkSize = item.Length - _screenWidth;
string chunk = item.Substring(0, _screenWidth);
line.Append($"{chunk} ");
Line(ref line, item);
item = item.Substring(_screenWidth, chunkSize);
Item(ref line, item);
}
else
{
line.Append($"{item} ");
}
}
}
}
Its already implemented on Colorify - C# NETCore Console Library with Text Format: colors, alignment and lot more [ for Win, Mac & Linux ]
You should probably be able to utilize Console.WindowWidth with some look-ahead newline logic to make this happen.

Get number of lines in file and add first 40 characters

As part of an assignment -
The User selects a file extension (.txt, .bat, or .xyz)
A list of files from a folder with that extension is shown
The user then selects a file from the list and are shown the first 40 characters of each of its first four lines (or as many lines as present if less than four lines are recorded in the file). If there are more lines left in the file, output a string: “xx more lines are not shown.” (substitute xx with the correct number).
I can't seem to wrap my head around number 3. Any help or pointers are greatly appreciated.
namespace unit9Assignment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//add the extensions to the c box.
comboBox1.Items.Add(".txt");
comboBox1.Items.Add(".xyz");
comboBox1.Items.Add(".bat");
//make .txt the default selection
comboBox1.SelectedItem = ".txt";
tabControl1.SelectedIndexChanged += tabControl1_SelectedIndexChanged;
}
/******Tab Click Event********/
private void tabControl1_SelectedIndexChanged(Object sender, EventArgs e)
{
switch ((sender as TabControl).SelectedIndex)
{
case 0:
break;
case 1:
fileName(comboBox1.Text);
break;
case 2:
fileContent(Files.SelectedItem.ToString());
break;
}
}
/******Get Files Based on Selection*******/
public void fileName(string fileExt)
{
List<string> listOfFiles = new List<string>();
string[] fileExtArray = Directory.GetFiles(#"C:\Users\Public", "*" + fileExt);
foreach (string fileExtFile in fileExtArray)
{
listOfFiles.Add(fileExtFile);
}
Files.DataSource = listOfFiles;
}
/******Display 4 Lines # 40 Characters Per Line*********/
public void fileContent(string fileName)
{
int numberOfLines = File.ReadLines(#fileName).Count(),
remainingLines = numberOfLines - 4;
//THIS PRINTS OUT 4 LINES # 40 CHARACTERS PER LINE IF A FILE HAS LESS THAN 5 LINES
if (numberOfLines < 5)
{
foreach (string line in File.ReadLines(fileName))
{
richTextBox1.AppendText(line.Substring(0, 40) + Environment.NewLine);
Console.WriteLine(line.Substring(0, 40));
}
}
// NO CLUE WHAT TO DO
else
{
}
}
}
}
Rather than checking the number of lines in the file, why don't you just go ahead and start printing, and stop after 4 lines? Something like this:
StreamReader fileIn = new StreamReader(fileName);
for(int i=0; i<4 && !fileIn.EndOfStream; ++i)
{
string line = fileIn.ReadLine();
if(line.Length > 40)
richTextBox1.AppendText(line.Substring(0,40) + Environment.NewLine);
else
richTextBox1.AppendText(line + Environment.NewLine);
}
int j;
for(j=0; !fileIn.EndOfStream; ++j)
fileIn.ReadLine();
if(j>0)
richTextBox1.AppendText(j.ToString() + " more lines are not shown.";
fileIn.Close();
... To clarify, this would be your entire fileContent method. You actually do not need to know the number of lines in the file. Of course, this method won't work if you have more lines in your file than an int variable can hold, but I assume you're not working with such long files.
How about this:
public void fileContent(string fileName)
{
var lines = File.ReadLines(#fileName);
foreach (string line in lines.Take(4))
{
richTextBox1.AppendText(line.Substring(0, 40) + Environment.NewLine);
}
var remaining = lines.Count() - 4;
if (remaining > 0)
richTextBox1.AppendText(remaining + " more line(s) are not shown.");
}
The Take() documentation is here.
Giving answers to homework is bad practice. Instead here are some pointers to help you wrap your head around your problem:
//read a file
var lines = File.ReadLines("myfile");
//get the first 4 lines of your file
var first4 = lines.Take(4);
//get the first 40 characters of the first line of your file
var first40Chars = lines.FirstOrDefault().Take(40);
//get the remaining number of lines
var remainingCount = lines.Count() - 4;
Pulling up a dialog to show files is quite easy also. The WinForms FileDialog can help you there.

Writing rows from a DataTable is creating a run-on write: how do I preserve each line as it is written?

Given this code:
using (StreamWriter sw = File.CreateText(file))
{
for (int r = 0; r < originalDataTable.Rows.Count; r++)
{
for (int c = 0; c < originalDataTable.Columns.Count; c++)
{
var rowValueAtColumn = originalDataTable.Rows[r][c].ToString();
var valueToWrite = string.Format(#"{0}{1}", rowValueAtColumn, "\t");
if (c != originalDataTable.Columns.Count)
sw.Write(valueToWrite);
else
sw.Write(valueToWrite + #"\n");
}
}
}
I am trying to write a DataRow back to a file one row at a time; however, the file it is creating is creating a run-on sentence where all the data being written to the file is just in one line. There should be 590 individual lines not just one.
What do I need to add to the code above so that my lines are broken out as they are in the data table? My code just doesn't seem to be working.
sw.Write(valueToWrite + #"\n"); is wrong. Because of the # it is not entering a newline, you are writing the character \ then the character n.
You want to do either sw.Write(valueToWrite + "\n"); or have the program put a new line in for you by doing sw.WriteLine(valueToWrite), however that will enter Environment.NewLine which is \r\n on windows.
However you can make your code even simpler by inserting the row the separator outside of the column for loop. I also defined the two separators at the top of the loop in case you want to ever change them (What will the program you are sending this to do when you hit some data that has a \t or a \n in the text itself?), and a few other small tweaks to make the code easier to read.
string colSeperator = "\t";
string rowSeperator = "\n";
using (StreamWriter sw = File.CreateText(file))
{
for (int r = 0; r < originalDataTable.Rows.Count; r++)
{
for (int c = 0; c < originalDataTable.Columns.Count; c++)
{
sw.Write(originalDataTable.Rows[r][c])
sw.Write(colSeperator);
}
sw.Write(rowSeperator);
}
}
Here is another similification just to show other ways to do it (now that you don't need to check originalDataTable.Columns.Count)
string colSeperator = "\t";
string rowSeperator = "\n";
using (StreamWriter sw = File.CreateText(file))
{
foreach (DataRow row in originalDataTable.Rows)
{
foreach (object value in row.ItemArray))
{
sw.Write(value)
sw.Write(colSeperator);
}
sw.Write(rowSeperator);
}
}
Change sw.Write() to sw.WriteLine()
http://msdn.microsoft.com/en-us/library/system.io.streamwriter.writeline.aspx

Categories