Split the line and add it in front of next chunk - c#

I convert each chunk as string. How I find the last line fed, spilt it from this chunk if does not end with closing bracket "}". And keep that line to add it in front of the next chunk.
Code:
if (rslt.Byte != null)
{
// How to check if content ends with "}",
// If no, keep that line to add it in front of next chunk.
content = System.Text.Encoding.Default.GetString(rslt.Byte);
}

Thank you and I post it as answer. Hoping it can help more people.
if (!content.TrimEnd().EndsWith("}")) {
int lastBracketIndex = content.LastIndexOf("}");
string lastLine = content.Substring(lastBracketIndex + 1);
content = content.Substring(0, lastBracketIndex + 1); }

Related

How to read text from file from one value to other in c#

I`m new in c#, I'm still learning that language. Now I try to make app which read text and to my data i need only specific lines. Text look like:
[HAEDING]
Some value
[HEADING]
Some other value
[HEADING]
Some other text
and continuation of this text in new line
[HEADING]
Last text
I try to write method which read text and put it into string[] by split it like this:
string[0] = Some value
string[1] = Some other value
string[2] = Some other text and continuation of this text in new line
string[3] = Last text
So I want to read line from value [HEADING] to value new line which is empty. I thought that is should write by ReadAllLines and line by line check start position on value [HEADING] and end position on empty value in new line. I try this code:
string s = "mystring";
int start = s.IndexOf("[HEADING]");
int end = s.IndexOf("\n", start);
string result = s.Substring(start, end - start);
but it's substring to all lines in my text not like loop between first [HEADING] and empty new line, second etc.
Maybe someone can help me with this?
You could try to split the string by "[HEADING]" to get the strings between these lines. Then you could join each string into a single line and trim the whitespace around the strings:
string content = #"[HEADING]
Some value
[HEADING]
Some other value
[HEADING]
Some other text
and continuation of this text in new line
[HEADING]
Last text";
var segments = content.Split(new[] { "[HEADING]"}, StringSplitOptions.RemoveEmptyEntries) // Split into multiple strings
.Select(p=>p.Replace("\r\n"," ").Replace("\r"," ").Replace("\n"," ").Trim()) // Join each single string into single line
.ToArray();
Result:
segments[0] = "Some value"
segments[1] = "Some other value"
segments[2] = "Some other text and continuation of this text in new line"
segments[3] = "Last text"
Here's a solution which avoids the substring/index checking, which could potentially be fraught with errors.
There are answers such as this one that use LINQ, but for a newcomer to the language, basic looping is an OK place to start. Also, this is not necessarily the best solution for efficiency or whatever.
This foreach loop will handle your case, and some of the "dirty" cases.
var segments = new List<string>();
bool headingChanged = false;
foreach (var line in File.ReadAllLines("somefilename.txt"))
{
// skip blank lines
if (string.IsNullOrWhitespace(line)) continue;
// detect a heading
if (line.Contains("[HEADING]")
{
headingChanged = true;
continue;
}
if (headingChanged)
{
segments.Add(line);
// this keeps us working on the same segment if there
// are more lines to be added to the segment
headingChanged = false;
}
else
{
segments[segments.Length - 1] += " ";
segments[segments.Length - 1] += line;
// you could replace the above two lines with string interpolation...
// segments[segments.Length - 1] = $"{segments[segments.Length - 1]} {line}";
}
}
In the above loop, the ReadAllLines obviates the need to check for \r and \n. Contains will handle [HEADING] no matter where it changes.
You don't need substring, you can just compare the value s == "[HEADING]".
Here's an easy to understand example:
var lines = System.IO.File.ReadAllLines(myFilePath);
var resultLines = new List<String>();
var collectedText = new List<String>();
foreach (var line in lines)
{
if (line == "[HEADING]")
{
collectedText = new List<String>();
}
else if (line != "")
{
collectedText.Add(line);
}
else //if (line == "")
{
var joinedText = String.Join(" ", collectedText);
resultLines.Add(joinedText);
}
}
return resultLines.ToArray();
the loop does this:
we go line by line
"start collecting" (create list) when we encounter with "[HEADING]" line
"collect" (add to list) line if not empty
"finish collecting" (concat and add to results list) when line is empty

C# removing last line in string

I'm using C# (unity3d).
I have a string containing lines separated by \r\n, and I need to remove the last line.
z
I managed to make something work but it takes 3 lines, I feel that maybe there could be something shorter in C# to do that.
Here is my current code :
int index = infoTxt.text.LastIndexOf("\r\n");
infoTxt.text = infoTxt.text.Substring(0, index - 2);
infoTxt.text = infoTxt.text.Substring(0, infoTxt.text.LastIndexOf("\r\n")+2);
Is this efficient enough to be used often, with a text string growing as time goes on ?
This is for a console-like system.
You can achieve this by simply doing:
var trimmed = text.Substring(0, text.LastIndexOf("\r\n"));
Tested with:
var text = File.ReadAllText("data.txt"); // "row1\r\nrow2\r\nrow3"
var trimmed = text.Substring(0, text.LastIndexOf("\r\n")); // "row1\r\nrow2"
Your double sub-stringing suggests your data ends with an empty line. If so then you need the second last index of it:
string value = "\r\n";
var text = File.ReadAllText("data.txt"); //"row1\r\nrow2\r\nrow3\r\n"
int lastPosition = text.LastIndexOf(value);
var trimmed = text.Substring(0, text.LastIndexOf(value, lastPosition-1)); // "row1\r\nrow2"
Last - see #serge.karalenka suggestion to use Environment.NewLine instead of "\r\n"
If you have and option of no new lines then you should:
var trimmed = text.Substring(0, lastPosition == -1 ? text.Length :
text.LastIndexOf(Environment.NewLine, lastPosition - 1));
You override the results of the 2nd line with your 3rd line (just adding "\r\n" to it).
Also, you can use Environment.NewLine instead of "\r\n", so your code will be cross-platform.
So just one line will suffice for your task:
var trimmed = text.Substring(0, text.LastIndexOf(Environment.NewLine));

C# Syntax - Remove last occurrence of ';' in string from split

I have a list of strings stored in an ArrayList. I want to split them by every occurrence of ';'. The problem is, whenever I try to display them using MessageBox, there's an excess space or unnecessary value that gets displayed.
Sample input (variable = a):
Arial;16 pt;None;None;None;None;None;None;FF0000;None;100;Normal;None;Normal;
Below is a line of code I used to split them:
string[] display_document = (a[0] + "").Split(';');
Code to display:
foreach (object doc_properties in display_document)
{
TextBox aa = new TextBox();
aa.Font = new Font(aa.Font.FontFamily, 9);
aa.Text = doc_properties.ToString();
aa.Location = new Point(pointX, pointY);
aa.Size = new System.Drawing.Size(80, 25);
aa.ReadOnly = true;
doc_panel.Controls.Add(aa);
doc_panel.Show();
pointY += 30;
}
The output that displays are the following:
How do I remove the last occurrence of that semicolon? I really need help fixing this. Thank you so much for all of your help.
Wouldnt It be easiest to check if the input ends with a ";" before splitting it, and if so remove the last character? Sample code:
string a = "Arial;16 pt;None;None;None;None;None;None;FF0000;None;100;Normal;None;Normal;";
if (a.EndsWith(";"))
{
a = a.Remove(a.LastIndexOf(";"));
}
//Proceed with split
Split will not print last semicolon if no space character is added and your input is a string.
I don't know why you prefer an array list (which probably is the reason of this strange behaviour) but if you could use your input as a string you could try that
string a = "Arial;16pt;None;None;None;None;None;None;FF0000;None;100;Normal;None;Normal;";
string[] display_document = a.Split(';');
foreach (object doc_properties in display_document)
{
//The rest of your code
}

Alternative to File.AppendAllText for newline

I am trying to read characters from a file and then append them in another file after removing the comments (which are followed by semicolon).
sample data from parent file:
Name- Harly Brown ;Name is Harley Brown
Age- 20 ;Age is 20 years
Desired result:
Name- Harley Brown
Age- 20
I am trying the following code-
StreamReader infile = new StreamReader(floc + "G" + line + ".NC0");
while (infile.Peek() != -1)
{
letter = Convert.ToChar(infile.Read());
if (letter == ';')
{
infile.ReadLine();
}
else
{
System.IO.File.AppendAllText(path, Convert.ToString(letter));
}
}
But the output i am getting is-
Name- Harley Brown Age-20
Its because AppendAllText is not working for the newline. Is there any alternative?
Sure, why not use File.AppendAllLines. See documentation here.
Appends lines to a file, and then closes the file. If the specified file does not exist, this method creates a file, writes the specified lines to the file, and then closes the file.
It takes in any IEnumerable<string> and adds every line to the specified file. So it always adds the line on a new line.
Small example:
const string originalFile = #"D:\Temp\file.txt";
const string newFile = #"D:\Temp\newFile.txt";
// Retrieve all lines from the file.
string[] linesFromFile = File.ReadAllLines(originalFile);
List<string> linesToAppend = new List<string>();
foreach (string line in linesFromFile)
{
// 1. Split the line at the semicolon.
// 2. Take the first index, because the first part is your required result.
// 3. Trim the trailing and leading spaces.
string appendAbleLine = line.Split(';').FirstOrDefault().Trim();
// Add the line to the list of lines to append.
linesToAppend.Add(appendAbleLine);
}
// Append all lines to the file.
File.AppendAllLines(newFile, linesToAppend);
Output:
Name- Harley Brown
Age- 20
You could even change the foreach-loop into a LINQ-expression, if you prefer LINQ:
List<string> linesToAppend = linesFromFile.Select(line => line.Split(';').FirstOrDefault().Trim()).ToList();
Why use char by char comparison when .NET Framework is full of useful string manipulation functions?
Also, don't use a file write function multiple times when you can use it only one time, it's time and resources consuming!
StreamReader stream = new StreamReader("file1.txt");
string str = "";
while ((string line = infile.ReadLine()) != null) { // Get every line of the file.
line = line.Split(';')[0].Trim(); // Remove comment (right part of ;) and useless white characters.
str += line + "\n"; // Add it to our final file contents.
}
File.WriteAllText("file2.txt", str); // Write it to the new file.
You could do this with LINQ, System.File.ReadLines(string), and System.File.WriteAllLines(string, IEnumerable<string>). You could also use System.File.AppendAllLines(string, IEnumerable<string>) in a find-and-replace fashion if that was, in fact, the functionality you were going for. The difference, as the names suggest, is whether it writes everything out as a new file or if it just appends to an existing one.
System.IO.File.WriteAllLines(newPath, System.IO.File.ReadLines(oldPath).Select(c =>
{
int semicolon = c.IndexOf(';');
if (semicolon > -1)
return c.Remove(semicolon);
else
return c;
}));
In case you aren't super familiar with LINQ syntax, the idea here is to loop through each line in the file, and if it contains a semicolon (that is, IndexOf returns something that is over -1) we cut that off, and otherwise, we just return the string. Then we write all of those to the file. The StreamReader equivalent to this would be:
using (StreamReader reader = new StreamReader(oldPath))
using (StreamWriter writer = new StreamWriter(newPath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
int semicolon = line.IndexOf(';');
if (semicolon > -1)
line = c.Remove(semicolon);
writer.WriteLine(line);
}
}
Although, of course, this would feed an extra empty line at the end and the LINQ version wouldn't (as far as I know, it occurs to me that I'm not one hundred percent sure on that, but if someone reading this does know I would appreciate a comment).
Another important thing to note, just looking at your original file, you might want to add in some Trim calls, since it looks like you can have spaces before your semicolons, and I don't imagine you want those copied through.

Reading multiple lines of text if it starts with a specific token

:58A:/C/81000098099CL
CBNINGLA
:72:/CODTYPTR/012
/CLEARING/0003
/SGI/DBLNNGLA
am trying to read the swift message above, line :58A: and line :72:, am having a little issue. My code only reads line :58A: like this C/81000098099CL, but I want it to read down the line before getting to line :72:, in short, the output should be like this for line :58A: C/81000098099CL CBNINGLA.
Same also for line :72:, this is because the messages come formatted in this form. This is my code below
if (line.StartsWith(":58A:"))
{
string[] narr = line.Split('/');
inflow202.BENEFICIARY_INSTITUTION = narr[2];
}
if (line.StartsWith(":72:"))
{
inflow202.RECEIVER_INFORMATION = line.Substring(5);
}
You can replace all new lines not followed by : with spaces (or empty string).
string output = Regex.Replace(text, #"\r?\n(?!:)", " ");
string[] lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (line.StartsWith(":58A:"))
{
}
else if (line.StartsWith(":72:"))
{
}
}
If the message always comes formatted in this form and : never occurs in the text except for these line starters, consider splitting the whole text into an array by : first. On 0th position there will be nothing, on all odd positions will be the number, on all even positions will be the content until next :. This solution will work providing that you are able to read the whole input into a single string first. I.e. having string message, you can do something like:
var splitted = message.Split(':');
for (i=1;i<= splitted.Length -1; i+=2){
if (splitted[i] == "58A") {
//do what you need to do, the text you need is stored in splitted[i+1]
}
...
}

Categories

Resources