I need to split a string into newlines in .NET and the only way I know of to split strings is with the Split method. However that will not allow me to (easily) split on a newline, so what is the best way to do it?
To split on a string you need to use the overload that takes an array of strings:
string[] lines = theText.Split(
new string[] { Environment.NewLine },
StringSplitOptions.None
);
Edit:
If you want to handle different types of line breaks in a text, you can use the ability to match more than one string. This will correctly split on either type of line break, and preserve empty lines and spacing in the text:
string[] lines = theText.Split(
new string[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
What about using a StringReader?
using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
string line = reader.ReadLine();
}
Try to avoid using string.Split for a general solution, because you'll use more memory everywhere you use the function -- the original string, and the split copy, both in memory. Trust me that this can be one hell of a problem when you start to scale -- run a 32-bit batch-processing app processing 100MB documents, and you'll crap out at eight concurrent threads. Not that I've been there before...
Instead, use an iterator like this;
public static IEnumerable<string> SplitToLines(this string input)
{
if (input == null)
{
yield break;
}
using (System.IO.StringReader reader = new System.IO.StringReader(input))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
This will allow you to do a more memory efficient loop around your data;
foreach(var line in document.SplitToLines())
{
// one line at a time...
}
Of course, if you want it all in memory, you can do this;
var allTheLines = document.SplitToLines().ToArray();
You should be able to split your string pretty easily, like so:
aString.Split(Environment.NewLine.ToCharArray());
Based on Guffa's answer, in an extension class, use:
public static string[] Lines(this string source) {
return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}
Regex is also an option:
private string[] SplitStringByLineFeed(string inpString)
{
string[] locResult = Regex.Split(inpString, "[\r\n]+");
return locResult;
}
For a string variable s:
s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)
This uses your environment's definition of line endings. On Windows, line endings are CR-LF (carriage return, line feed) or in C#'s escape characters \r\n.
This is a reliable solution, because if you recombine the lines with String.Join, this equals your original string:
var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
var reconstituted = String.Join(Environment.NewLine,lines);
Debug.Assert(s==reconstituted);
What not to do:
Use StringSplitOptions.RemoveEmptyEntries, because this will break markup such as Markdown where empty lines have syntactic purpose.
Split on separator new char[]{Environment.NewLine}, because on Windows this will create one empty string element for each new line.
I just thought I would add my two-bits, because the other solutions on this question do not fall into the reusable code classification and are not convenient.
The following block of code extends the string object so that it is available as a natural method when working with strings.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.ObjectModel;
namespace System
{
public static class StringExtensions
{
public static string[] Split(this string s, string delimiter, StringSplitOptions options = StringSplitOptions.None)
{
return s.Split(new string[] { delimiter }, options);
}
}
}
You can now use the .Split() function from any string as follows:
string[] result;
// Pass a string, and the delimiter
result = string.Split("My simple string", " ");
// Split an existing string by delimiter only
string foo = "my - string - i - want - split";
result = foo.Split("-");
// You can even pass the split options parameter. When omitted it is
// set to StringSplitOptions.None
result = foo.Split("-", StringSplitOptions.RemoveEmptyEntries);
To split on a newline character, simply pass "\n" or "\r\n" as the delimiter parameter.
Comment: It would be nice if Microsoft implemented this overload.
Starting with .NET 6 we can use the new String.ReplaceLineEndings() method to canonicalize cross-platform line endings, so these days I find this to be the simplest way:
var lines = input
.ReplaceLineEndings()
.Split(Environment.NewLine, StringSplitOptions.None);
I'm currently using this function (based on other answers) in VB.NET:
Private Shared Function SplitLines(text As String) As String()
Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
End Function
It tries to split on the platform-local newline first, and then falls back to each possible newline.
I've only needed this inside one class so far. If that changes, I will probably make this Public and move it to a utility class, and maybe even make it an extension method.
Here's how to join the lines back up, for good measure:
Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
Return String.Join(Environment.NewLine, lines)
End Function
Well, actually split should do:
//Constructing string...
StringBuilder sb = new StringBuilder();
sb.AppendLine("first line");
sb.AppendLine("second line");
sb.AppendLine("third line");
string s = sb.ToString();
Console.WriteLine(s);
//Splitting multiline string into separate lines
string[] splitted = s.Split(new string[] {System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
// Output (separate lines)
for( int i = 0; i < splitted.Count(); i++ )
{
Console.WriteLine("{0}: {1}", i, splitted[i]);
}
string[] lines = text.Split(
Environment.NewLine.ToCharArray(),
StringSplitOptions.RemoveEmptyStrings);
The RemoveEmptyStrings option will make sure you don't have empty entries due to \n following a \r
(Edit to reflect comments:) Note that it will also discard genuine empty lines in the text. This is usually what I want but it might not be your requirement.
I did not know about Environment.Newline, but I guess this is a very good solution.
My try would have been:
string str = "Test Me\r\nTest Me\nTest Me";
var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();
The additional .Trim removes any \r or \n that might be still present (e. g. when on windows but splitting a string with os x newline characters). Probably not the fastest method though.
EDIT:
As the comments correctly pointed out, this also removes any whitespace at the start of the line or before the new line feed. If you need to preserve that whitespace, use one of the other options.
Examples here are great and helped me with a current "challenge" to split RSA-keys to be presented in a more readable way. Based on Steve Coopers solution:
string Splitstring(string txt, int n = 120, string AddBefore = "", string AddAfterExtra = "")
{
//Spit each string into a n-line length list of strings
var Lines = Enumerable.Range(0, txt.Length / n).Select(i => txt.Substring(i * n, n)).ToList();
//Check if there are any characters left after split, if so add the rest
if(txt.Length > ((txt.Length / n)*n) )
Lines.Add(txt.Substring((txt.Length/n)*n));
//Create return text, with extras
string txtReturn = "";
foreach (string Line in Lines)
txtReturn += AddBefore + Line + AddAfterExtra + Environment.NewLine;
return txtReturn;
}
Presenting a RSA-key with 33 chars width and quotes are then simply
Console.WriteLine(Splitstring(RSAPubKey, 33, "\"", "\""));
Output:
Hopefully someone find it usefull...
Silly answer: write to a temporary file so you can use the venerable
File.ReadLines
var s = "Hello\r\nWorld";
var path = Path.GetTempFileName();
using (var writer = new StreamWriter(path))
{
writer.Write(s);
}
var lines = File.ReadLines(path);
using System.IO;
string textToSplit;
if (textToSplit != null)
{
List<string> lines = new List<string>();
using (StringReader reader = new StringReader(textToSplit))
{
for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
lines.Add(line);
}
}
}
Very easy, actually.
VB.NET:
Private Function SplitOnNewLine(input as String) As String
Return input.Split(Environment.NewLine)
End Function
C#:
string splitOnNewLine(string input)
{
return input.split(environment.newline);
}
I have created a text file with some random float numbers ranging from 743.6 to 1500.4.
I am figuring out a way to read the text file (which i have did) and include a number range: lets say( 743.6 <= x <= 800) and remove the numbers which are outside the range and eventually store the final values in a text file.
I have managed to write some codes to read the text file so that when i compile it shows the numbers in the text file. Now i do not know how to progress further . Here is my code, which is able to run compile. This code now ables to read the textfile.
743.6
742.8
744.7
743.2
1000
1768.6
1750
1767
1780
1500
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ReadTextFile
{
class Program
{
static void Main(string[] args)
{
string filePath = "C:\\Users\\Student\\Desktop\\ConsoleApp1\\ConsoleApp1\\Data\\TextFile.txt"; // File Direcotry
List<string> lines = File.ReadAllLines(filePath).ToList();
foreach (string line in lines)
{
Console.WriteLine(line);
}
Console.ReadLine();
}
}
}
This will read the file into memory, parse it, filter it and than overwrite the existing file with the new data.
File.WriteAllLines(filePath,
File.ReadAllLines(filePath)
.Select(x => double.Parse(x))
.Where(x => x >= 800.5 && x <= 850.5)
.Select(x => x.ToString()));
Here's my solution w/ basic error detection and some robustness thanks to the use of regular expressions.
As a foreword: Using regular expressions can be quite expensive and they are not always the way to go.
In this case I think they're okay, because you're handling user-generated input (possibly).
Regular expressions can be optimised by pre-compiling them!
/*
using System;
using System.IO;
using System.Text.RegularExpressions;
*/
void ReadFile(string filePath) {
var fileInfo = default(FileInfo);
var separator = #"[;\s:,]"; // This is a simple RegEx, can be done otherwise. This allows for a little more robustness IMO
// VERY rudimentary error detection
if (string.IsNullOrEmpty(filePath))
throw new ArgumentNullException(nameof(filePath), "The path to the file must not be null or empty!");
try {
fileInfo = new FileInfo(filePath);
} catch {
throw new ArgumentException(nameof(filePath), "A valid path must be given!");
}
if (!fileInfo.Exists) {
throw new IOException(string.Format("The file {0} does not exist!", filePath));
}
// END VERY rudimentary error checking
var numberStrings = Regex.Split(File.ReadAllText(fileInfo.FullName), separator);
// numberStrings is now an array of strings
foreach (var numString in numberStrings) {
if (decimal.TryParse(numString, out var myDecimal)) {
// Do something w/ number
} else {
Debug.WriteLine("{0} is NaN!", numString);
}
}
}
Here's what the code does (written off the top of my head, please don't just C&P it. Test it first):
At first we're defining the regular expression. This matches any character in the range (between the brackets).
Then we're performing very basic error checking:
If the argument passed is null or empty throw an exception
If we couldn't parse the argument to a FileInfo object, the path is likely invalid. Throw an exception.
If the file doesn't exist, throw an exception.
Next we're reading the entire text file in to memory (not on a per-line basis!) and using the regular expression we've defined to split the entire string in to an array of strings.
At last we're looping through our array of strings and parsing each number to a float (that's what you wanted. I personally would use a double or decimal for more precision. See this video from Tom Scott.).
If the string doesn't parse to a float, then you can handle the error accordingly. Otherwise do what you need to with the variable myFloat.
EDIT:
I thought I read you wanting to use floats. My mistake; I changed the datatype to decimal.
You need to read all the lines and replace all values between your min and max value with an empty string:
float min = 800.5F, max = 850.5F;
float currentValue;
var lines = File.ReadAllLines(usersPath);
var separator = ';'; // Change this according to which separator you're using between your values (if any)
foreach (var line in lines)
{
foreach (string word in line.Trim().Split(separator))
{
if (float.TryParse(word.Trim(), out currentValue))
{
if (currentValue < min || currentValue > max)
{
line.Replace(word, "");
}
}
}
}
File.WriteAllLines(usersPath, lines);
I have file contains two lines and each line contains 200 fields and I would like to split it into arrays
using (StreamReader sr = File.OpenText(pathSensorsCalc))
{
string s = String.Empty;
while ((s = sr.ReadLine()) == null) { };
String line1 = sr.ReadToEnd();
String line2 = sr.ReadToEnd();
CalcValue[0] = new String[200];
CalcValue[1] = new String[200];
CalcValue[0] = line1.Split(' ');
CalcValue[1] = line2.Split(' ');
}
After the code above, CalcValue[1] is empty and CalcValue[0] contains data of the second line (instad of the first one). Any ideas?
When using
sr.ReadToEnd()
, you are reading to the end of your input stream. That means, after the first call of
String line1 = sr.ReadToEnd()
your stream is already at the last position. Replace your ReadToEnd() call with ReadLine() calls. That should work.
In the Windows OS, a new line is represented by \r\n. So you should not split the lines by spaces (" ").
Which means you should use another overload of the Split method - Split(char[], StringSplitOptions). The first argument is the characters you want to split by and the second is the options. Why do you need the options? Because if you split by 2 continuous characters you get an empty element.
So now it is easy to understand what this code does and why:
line1.Split (new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
This is my code:
string path = #"c:\temp\mytext.txt";
string[] lines = System.IO.File.ReadAllLines(path);
foreach (var line in lines)
{
var firstValue = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)[0];
Console.WriteLine(firstValue);
System.IO.File.WriteAllLines(#"C:\temp\WriteLines.txt", firstValue);
}
I want to export my first value to a text file. How i can export it?
I get this error:
Cannot convert from 'string' to 'System.Collections.Generic.IEnumerable'
at this line
System.IO.File.WriteAllLines(#"C:\temp\WriteLines.txt", firstValue);
File.WriteAllLines takes a sequence of strings - you've only got a single string.
If you only want your file to contain that single string, just use File.WriteAllText:
File.WriteAllText(#"C:\temp\WriteLines.txt", firstValue);
However, given that you've got this in a loop it's going to keep replacing the contents of the file with the first part of each line of the input file.
If you're trying to get the first part of each line of your input file into your output file, you'd be better off with:
var query = File.ReadLines(inputFile)
.Select(line => line.Split(new string[] { " " },
StringSplitOptions.RemoveEmptyEntries)[0]);
File.WriteAllLines(outputFile, query);
Note that with a using directive of
using System.IO;
you don't need to fully-qualify everything, so your code will be much clearer.
When I press a button the following happens:
HttpWebRequest request = (HttpWebRequest)WebRequest
.Create("http://oldschool.runescape.com/slu");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
richTextBox1.Text = sr.ReadToEnd();
sr.Close();
In short the data gets transferred to my textbox (this works perfectly)
Now if I choose world 78 (for example, from a combobox, it will refer to the last digits of that line) I want to get the value 968, if i choose world 14, I want to get the value 973.
This is an example of the printed data
e(378,true,0,"oldschool78",968,"United States","US","Old School 78");
e(314,true,0,"oldschool14",973,"United States","US","Old School 14");
What can I use to read this?
So there are two problems here, the first is selecting the right line, then getting the number out.
First you want a method for getting each of the lines in to a list, eg using something like this:
List<String> lines = new List<String>()
string line = sr.ReadLine();
while(line != null)
{
lines.Add(line);
line = sr.ReadLine(); // read the next line
}
Then you need to find the relevant line and get the token out of it.
Probably the most simple way is, for each line, split the string up by ',', '\"', '(' and ')' (using
String.Split). Ie, we get basically the parameters.
Eg
foreach(string lineInFile in lines)
{
// split the string in to tokens
string[] tokens = lineInFile.Split(',', '\"', '(', ')');
// based on the sample strings and how we've split this,
// we take the 15th entry
string endParameter = tokens[15]; //endParamter = "Old School 14"
...
We now use a regular expression to extract the number. The pattern we will use is d+, ie 1 or more digits.
Regex numberFinder = new Regex("\\d+");
Match numberMatch = numberFinder.Match(endParameter);
// we assume that there is a match, because if there isn't the string isn't
// correct, you should do some error handling here
string matchedNumber = numberMatch.Value;
int value = Int32.Parse(matchedValue); // we convert the string in to the number
if(value == desiredValue)
...
We check if the value matches the value we were looking for (eg 14), we now need to get the number you wanted.
We've already split the parameters, and the number we want is the 8th item (eg index 7 in string[] tokens). Since, at least in your example, this is just a lone number, we can just parse this to get the int.
{
return Int32.Parse(tokens[7]);
}
}
Again here we are assuming that the string is in the formats you showed, and you should do error protection here to.