Muszę podzielić ciąg na nowe wiersze w .NET, a jedynym sposobem, w jaki wiem, aby podzielić ciągi jest metoda Split . Jednak to nie pozwoli mi (łatwo) rozdzielić na nowej linii, więc jaki jest najlepszy sposób, aby to zrobić?
Muszę podzielić ciąg na nowe wiersze w .NET, a jedynym sposobem, w jaki wiem, aby podzielić ciągi jest metoda Split . Jednak to nie pozwoli mi (łatwo) rozdzielić na nowej linii, więc jaki jest najlepszy sposób, aby to zrobić?
Odpowiedzi:
Aby podzielić na ciąg, musisz użyć przeciążenia, które zajmuje tablicę ciągów:
string[] lines = theText.Split(
new[] { Environment.NewLine },
StringSplitOptions.None
);
Edycja:
jeśli chcesz obsługiwać różne typy podziałów linii w tekście, możesz użyć możliwości dopasowania więcej niż jednego łańcucha. Spowoduje to prawidłowe podzielenie każdego rodzaju podziału linii i zachowanie pustych linii i odstępów w tekście:
string[] lines = theText.Split(
new[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
Environment.NewLine
Właściwość zawiera domyślną nową linię dla systemu. Na przykład w systemie Windows "\r\n"
.
\n
pozostawiając \r
na końcu każdej linii, a następnie wypisuje linie z \r\n
między nimi.
\r
i \n
sekwencje (między innymi) mają szczególne znaczenie dla kompilatora C #. VB nie ma tych sekwencji ucieczki, więc zamiast nich są używane te stałe.
Co z używaniem StringReader
?
using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
string line = reader.ReadLine();
}
while
pętlę, którą należy dodać do tej odpowiedzi.
Powinieneś być w stanie dość łatwo rozdzielić łańcuch, na przykład:
aString.Split(Environment.NewLine.ToCharArray());
Staraj się unikać używania string.Split dla ogólnego rozwiązania, ponieważ będziesz używać więcej pamięci wszędzie, gdzie używasz funkcji - oryginalny string i podzielona kopia, zarówno w pamięci. Zaufaj mi, że może to być jeden wielki problem, gdy zaczynasz skalować - uruchom 32-bitową aplikację do przetwarzania wsadowego przetwarzającą 100 MB dokumentów, a będziesz miał problem z ośmioma równoległymi wątkami. Nie to, że byłem tam wcześniej ...
Zamiast tego użyj takiego iteratora;
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;
}
}
}
Umożliwi to wykonanie bardziej wydajnej pamięci wokół danych;
foreach(var line in document.SplitToLines())
{
// one line at a time...
}
Oczywiście, jeśli chcesz mieć to wszystko w pamięci, możesz to zrobić;
var allTheLines = document.SplitToLines.ToArray();
blah.SplitToLines..
np. document.SplitToLines...
?
this
parametry formalne, co czyni go metodą rozszerzenia.
W oparciu o odpowiedź Guffy w klasie rozszerzającej użyj:
public static string[] Lines(this string source) {
return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}
W przypadku zmiennej łańcuchowej s
:
s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)
Wykorzystuje to definicję zakończeń linii w twoim środowisku. W systemie Windows zakończeniami linii są CR-LF (znak powrotu karetki, przejście do wiersza) lub znakami zmiany znaczenia w języku C # \r\n
.
Jest to niezawodne rozwiązanie, ponieważ jeśli zrekombinujesz linie String.Join
, równa się to oryginalnemu ciągowi:
var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
var reconstituted = String.Join(Environment.NewLine,lines);
Debug.Assert(s==reconstituted);
Czego nie robić:
StringSplitOptions.RemoveEmptyEntries
, ponieważ spowoduje to uszkodzenie znaczników, takich jak Markdown, gdzie puste linie mają cel składniowy.new char[]{Environment.NewLine}
, ponieważ w systemie Windows spowoduje to utworzenie jednego pustego elementu ciągu dla każdej nowej linii.Regex jest również opcją:
private string[] SplitStringByLineFeed(string inpString)
{
string[] locResult = Regex.Split(inpString, "[\r\n]+");
return locResult;
}
"\r?\n"
.
Pomyślałem, że dodam moje dwa bity, ponieważ inne rozwiązania tego pytania nie mieszczą się w klasyfikacji kodów wielokrotnego użytku i nie są wygodne.
Poniższy blok kodu rozszerza string
obiekt, dzięki czemu jest on dostępny jako naturalna metoda podczas pracy z łańcuchami.
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);
}
}
}
Możesz teraz użyć .Split()
funkcji z dowolnego łańcucha w następujący sposób:
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);
Aby podzielić znak nowego wiersza, wystarczy przekazać "\n"
lub "\r\n"
jako parametr separatora.
Komentarz: Byłoby miło, gdyby Microsoft wdrożył to przeciążenie.
Environment.Newline
Korzystne jest trudne kodowania albo \n
czy \r\n
.
Environment.Newline
jest kompatybilny z wieloma platformami, a nie do pracy z plikami używającymi innych zakończeń linii niż obecny system operacyjny. Zobacz tutaj, aby uzyskać więcej informacji , więc tak naprawdę zależy to od tego, z czym współpracuje programista. Użycie polecenia Environment.Newline
gwarantuje, że nie ma spójności w typie powrotu linii między systemami operacyjnymi, gdzie „kodowanie na stałe” daje programistom pełną kontrolę.
.Newline
nie jest magią, pod maską są tylko ciągi, jak podano powyżej, oparte na przełączniku, czy działa na Uniksie, czy na Windowsie. Najbezpieczniejszym zakładem jest najpierw zamiana łańcucha dla wszystkich „\ r \ n”, a następnie podział na „\ n”. Niepowodzenie używania .Newline
oznacza pracę z plikami zapisanymi przez inne programy korzystające z innej metody podziału linii. Działa dobrze, jeśli wiesz, że za każdym razem, gdy plik jest odczytywany, zawsze używa podziału wiersza w bieżącym systemie operacyjnym.
foo = foo.Replace("\r\n", "\n"); string[] result = foo.Split('\n');
. Czy rozumiem poprawnie, że działa to na wszystkich platformach?
Obecnie używam tej funkcji (na podstawie innych odpowiedzi) w VB.NET:
Private Shared Function SplitLines(text As String) As String()
Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
End Function
Najpierw próbuje podzielić się na lokalną linię nowej platformy, a następnie wraca do każdej możliwej nowej linii.
Do tej pory potrzebowałem tego tylko w jednej klasie. Jeśli to się zmieni, prawdopodobnie zrobię to Public
i przeniosę do klasy użyteczności, a może nawet uczynię to metodą rozszerzenia.
Oto jak ponownie dołączyć do linii, dla pewności:
Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
Return String.Join(Environment.NewLine, lines)
End Function
"\r"
= powrót. "\r\n"
= powrót + nowa linia. (proszę przejrzeć ten post i zaakceptowane rozwiązanie tutaj
Właściwie podział powinien zrobić:
//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);
Opcja RemoveEmptyStrings sprawi, że nie będziesz mieć pustych wpisów, ponieważ \ n następuje po \ r
(Edytuj, aby odzwierciedlić komentarze :) Pamiętaj, że odrzuci również oryginalne puste wiersze w tekście. Zazwyczaj tego właśnie chcę, ale może to nie być twoje wymaganie.
Nie wiedziałem o Environment.Newline, ale myślę, że to bardzo dobre rozwiązanie.
Moja próba byłaby:
string str = "Test Me\r\nTest Me\nTest Me";
var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();
Dodatkowe .Trim usuwa wszelkie \ r lub \ n, które mogą być nadal obecne (np. Gdy w systemie Windows, ale dzieląc ciąg znaków ze znakami nowej linii). Prawdopodobnie nie jest to najszybsza metoda.
EDYTOWAĆ:
Jak poprawnie wskazano w komentarzach, usuwa to również wszelkie białe znaki na początku wiersza lub przed nowym wierszem. Jeśli chcesz zachować ten biały znak, użyj jednej z innych opcji.
Głupia odpowiedź: napisz do pliku tymczasowego, abyś mógł użyć czcigodnego
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);
var
, ponieważ nie definiuje typu zmiennej, więc możesz nie zrozumieć, jak korzystać z tego obiektu lub co reprezentuje ten obiekt. Dodatkowo pokazuje to pisanie linii i nawet nie określa nazwy pliku, więc wątpię, żeby to zadziałało. Następnie podczas czytania ścieżka do pliku nie jest ponownie określona. Zakładając, że path
to C:\Temp\test.txt
należy wtedy string[] lines = File.ReadLines(path);
.
Path.GetTempFileName
msdn.microsoft.com/en-us/library/... i mówi, że tworzy plik zerowy i zwraca „pełną ścieżkę tego pliku”. Mógłbym przysiąc, że próbowałem tego wcześniej i dał wyjątek, ponieważ nie znalazł pliku, ale zamiast tego zwrócił lokalizację folderu. Znam argumenty za użyciem var
, ale powiedziałbym, że NIE jest to zalecane, ponieważ nie pokazuje, czym jest obiekt zmiennej. To zaciemnia to.
Właściwie to bardzo łatwe.
VB.NET:
Private Function SplitOnNewLine(input as String) As String
Return input.Split(Environment.NewLine)
End Function
DO#:
string splitOnNewLine(string input)
{
return input.split(environment.newline);
}
Environment.NewLine
tak jak w VB.