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));
Related
I have this code written in C# but looks kind of "bad" and I would like to shorten it somehow and keep it clean and simple.
All this code works pretty fine but I want to know if there's any other way I can achieve the same thing.
EDIT: I forgot to mention that the firstLine has a bad date format attached with it, so it is like this: "This_is_my_first_line_20220126". So I split the string and then only join it with the corrected date. The problem is that I can never know how long the new string would be and I don't want to handle the code like this and go up to 100 parts.
Here's my code:
string correctDate = "26012022";
string[] lines = File.ReadAllLines("text.txt");
string firstLine = lines.FirstOrDefault();
//note: firstLine looks like this: This_is_my_first_line_20220126
string[] sub = firstLine.Split('_');
string name="";
if(sub.Length==2)
name = sub[0]+"_"+sub[1]+"_"+correctDate;
else if(sub.Length==3)
name = sub[0]+"_"+sub[1]+"_"+sub[2]+"_"correctDate;
...
else if(sub.Length==20)
name = sub[0]+"_"+ ... "_" + sub[19];
Now, my final name value should be "This_is_my_line_26012022" but I want it to depend on the length of the given string. So far I know that the maximum length would go up to 20 but I don't want my code to look like this. Can I shorten it somehow?
you can find the LastIndexOf the underscore and drop the date by using Substring:
string firstLine = "This_is_my_first_line_20220126";
string correctDate = "26012022";
string correctString = firstLine.Substring(0, firstLine.LastIndexOf("_") + 1) + correctDate;
Still a little perplexed with the split aproach, but this a way to join back all elements
string name = string.Join("_", sub.Take(sub.Length - 1).Append(correctDate));
Or use the substring method (and no need of all that split & join)
name = firstLine.Substring(0, firstLine.LastIndexOf("_") +1) + correctDate;
I forgot to mention that firstLine has a bad date format like "This_is_my_Line_20220125"
If you want to correct just the first line:
string correctDate = "26012022";
string[] lines = File.ReadAllLines("text.txt");
lines[0] = lines[0][..^8] + correctDate;
[..^8] uses C# 9's "indices and ranges" feature, that allows for a more compact way of taking a substring. It means "from the start of the string, up to the index 8 back from the end of the string".
If you get a wiggly line and possibly a messages like "... is not available in C# version X" you can use the older syntax, which would be more like lines[0] = lines[0].Remove(lines[0].Length - 8) + correctDate;
If you want to correct all lines:
string correctDate = "26012022";
string[] lines = File.ReadAllLines("text.txt");
for(int x = 0; x < lines.Length; x++)
lines[x] = lines[x][..^8] + correctDate;
If the incorrect date isn't always 8 characters long, you can use LastIndexOf('_') to locate the last _, and snip it to that point
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
I have a list of string where one item is like, textItem1 = "Brown, Adam. (user)(admin)(Sales)" where I would always have to extract the text from the last pair of parentheses, which in this case will be Sales.
I tried the following:
string name = DDlistName.SelectedItem.ToString();
int start = name.IndexOf("(");
int end = name.IndexOf("(");
string result = name.Substring(start + 1, end - start - 1);
_UILabelPrintName.Text = result;
Problem: This always picks the text from first pair of parentheses, which in this case user.
Reading lots of similar question's answer I realised Regex might not be recommended in this case (not particularly succeeded either trying other codes). However any help with any short routine which can do the task will be really appreciated.
You need to use LastIndexOf instead of IndexOf, and check for a close parenthesis at the end.
string name = "Brown, Adam. (user)(admin)(Sales)";
int start = name.LastIndexOf("(");
int end = name.LastIndexOf(")");
string result = name.Substring(start + 1, end - start - 1);
Really you'd want to validate start and end to be sure that both parenthesis were found. LastIndexOf returns -1 if the character is not found.
And in order to handle nesting we need to search forward for the closing parenthesis after the location of the opening parenthesis.
string name = "Brown, Adam. (user)(admin)((Sales))";
int start = name.LastIndexOf('(');
int end = (start >= 0) ? name.IndexOf(')', start) : -1;
string result = (end >= 0) ? name.Substring(start + 1, end - start - 1) : "";
You can use the split function, breaking the string at the opening parenthesis. The last array element is the desired output with a tailing ")", which will then be removed.
var input = "Brown, Adam. (user)(admin)(Sales)";
// var input = DDlistName.SelectedItem.ToString();
var lastPick = input.Split(new[] { "(" }, StringSplitOptions.RemoveEmptyEntries).Last();
var output = lastPick.Substring(0, lastPick.Length - 1);
_UILabelPrintName.Text = output;
Another approach is to use a while loop with IndexOf. It cuts the input string as long as another "(" is found. If not more "(" are found, it takes the contents of the remaining string until the closing parenthesis ")":
int current = -1;
while(name.IndexOf("(") > 0)
{
name = name.Substring(name.IndexOf("(") + 1);
}
var end = name.IndexOf(")");
var output = name.Substring(0, end);
_UILabelPrintName.Text = output;
Or use LastIndexOf....
In C# windows forms application I have strings of different length and format from which I would like to display a preview of the first 25 characters without containing any line breaks of any kind in the preview. The preview string should be followed by " ...".
I have some strings less than 25 chars but they also can contain line breaks or sometimes not. the newline can be like <br>, <br />, /n, /r, /r/n, /n/n or an Environment.Newline like in C#.
With shorter strings I get exceptions because of the TextX.SubString(0, 25) cannot be applied.
What ready function in the framework would do it the best way?
Maybe you have any idea how to solve this.
At the end should be appended the " ...", but since the string is already defined there can't be attached something to it TextX.Append doesn't exist in the content.
It seems, that there's no ready function in a framework, but you can do something like this:
public static String Preview(String value) {
String[] newLines = new String[] { "<br>", "<br />", "\n", "\r", Environment.NewLine };
foreach (String newLine in newLines)
value = value.Replace(newLine, ""); // <- May be space will be better here
if (text.Length > 25)
return value.Substring(0, 25) + "…";
// If you want string END, not string START, comment out the line above and uncomment this
// return value.Substring(value.Length - 25) + "…";
else
return value;
}
...
// Test sample
String text = "abcd<br>efgh\r\r\n\n1234567890zxy\n\n1234567890abc";
String result = Preview(text); // <- abcdefgh1234567890zxy1234…
String text2 = "abcd<br>efgh\r\r";
String result2 = Preview(text2); // <- abcdefgh
I want to display some bold and some simple content in the form so I am using richtextbox.And I have made one file with extension of .rtf.Now I load that file in the richtextbox with use of the Loadfile() function.This works. But I want to display particular content of the file in the richtextbox,like may be first five lines or it may be line no. of six to ten.Then is there any solution ??
It is possible, just not very cleanly. This code uses another RTB to load the file and the clipboard to get the formatted RTF. Beware that it destroys the clipboard content.
using (var helper = new RichTextBox()) {
helper.LoadFile(#"c:\temp\test.rtf");
// Copy line #6
int startRange = helper.GetFirstCharIndexFromLine(5);
int endRange = helper.GetFirstCharIndexFromLine(6);
helper.SelectionStart = startRange;
helper.SelectionLength = endRange - startRange;
helper.Copy();
}
richTextBox1.SelectAll();
richTextBox1.Paste();
This doesn't preserve any formatting, but shows how you could manipulate the Lines array. It looks like the RichTextBox selfishly keeps all RTF codes to itself and only exposes text through Lines:
var fromStart = new string[richTextBox1.Lines.Length - start];
Array.Copy(richTextBox1.Lines, start, fromStart, 0, fromStart.Length);
var lineSet = fromStart.Take(count).ToArray();
richTextBox1.Lines = lineSet;
start and count are passed into this function that selects a set of lines.
Solution using ReadAllLines:
string[] lines = File.ReadAllLines(filename);
int startLine = lines.IndexOf(startMarker);
int endLine = lines.IndexOf(endMarker);
if (startLine == -1 || endLine == -1)
{
// throw some sort of exception - the markers aren't present
}
string[] section = new string[endLine - startLine - 1];
Array.Copy(lines, startLine + 1, section, 0, section.Length);
richTextBox.Rtf = string.Join("\r\n", section);
Solution using ReadAllText:
string text = File.ReadAllText(filename);
int startIndex = text.IndexOf(startMarker);
int endIndex = text.IndexOf(endMarker, startIndex + startMarker.Length);
if (startIndex == -1 || endIndex == -1)
{
// throw some sort of exception - the markers aren't present
}
richTextBox.Rtf = text.Substring(startIndex + startMarker.Length,
endIndex - startIndex - startMarker.Length);
Both of these assume that you really have got a complete RTF document in that section of the file though - you may well find you need additional header text, for example. Also, both assume the file is in UTF-8. I don't know enough about the RTF format to know if that's correct.
Did you tried the Lines property? It allows set / get string array as the RichTextbox content.