Najłatwiejszym sposobem na podzielenie ciągu znaków na nowe wiersze w .NET?
806
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ć?
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:
@RCIX: Wysłanie poprawnych parametrów do metody jest nieco niewygodne, ponieważ używasz go do czegoś, co jest o wiele prostsze niż jest w stanie. Przynajmniej tam, przed framework 2
musiałeś
4
@Leandro: Environment.NewLineWłaściwość zawiera domyślną nową linię dla systemu. Na przykład w systemie Windows "\r\n".
Guffa
3
@Leandro: Można przypuszczać, że program dzieli się, \npozostawiając \rna końcu każdej linii, a następnie wypisuje linie z \r\nmiędzy nimi.
Guffa
3
@Samuel: \ri \nsekwencje (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.
Guffa,
2
Jeśli chcesz akceptować pliki z wielu różnych systemów operacyjnych, możesz również dodać „\ n \ r” na początku i „\ r” na końcu listy ograniczników. Nie jestem jednak pewien, czy warto trafić w wydajność. ( en.wikipedia.org/wiki/Newline )
W systemie innym niż * nix, który będzie dzielił się na osobne znaki w ciągu Newline, tj. Znaki CR i LF. To spowoduje dodatkowy pusty ciąg między każdą linią.
Guffa,
Popraw mnie, jeśli się mylę, ale czy to nie rozdzieli znaków?
RCIX 10.10.2009
7
@RCIX: Nie, kody \ ri \ n reprezentują pojedyncze znaki. Ciąg „\ r \ n” składa się z dwóch znaków, a nie czterech.
Guffa,
10
jeśli dodasz parametr StringSplitOptions.RemoveEmptyEntries, to będzie działać idealnie.
Ruben,
18
@Ruben: Nie, nie będzie. Serge zasugerował już to w swojej odpowiedzi, a ja już wyjaśniłem, że spowoduje to również usunięcie pustych linii w oryginalnym tekście, które należy zachować.
Guffa,
34
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 ...
Byłem tam ... (analizuję duże pliki HTML i brakuje pamięci). Tak, unikaj string.Split. Używanie string.Split może spowodować użycie Dużych Stert Obiektów (LOH) - ale nie jestem tego w 100% pewien.
Peter Mortensen
Jeśli uczyniłeś SplitToLines metodą statyczną (wydaje się, że dd), to jak możesz to zrobić blah.SplitToLines.. np. document.SplitToLines...?
barlop
ah Widzę, że wprowadzasz thisparametry formalne, co czyni go metodą rozszerzenia.
barlop
26
W oparciu o odpowiedź Guffy w klasie rozszerzającej użyj:
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(newstring[]{Environment.NewLine},StringSplitOptions.None);var reconstituted =String.Join(Environment.NewLine,lines);Debug.Assert(s==reconstituted);
Czego nie robić:
Użyj StringSplitOptions.RemoveEmptyEntries, ponieważ spowoduje to uszkodzenie znaczników, takich jak Markdown, gdzie puste linie mają cel składniowy.
Podziel na separatorze new char[]{Environment.NewLine}, ponieważ w systemie Windows spowoduje to utworzenie jednego pustego elementu ciągu dla każdej nowej linii.
Jeśli chcesz dopasować linie dokładnie, zachowując puste linie, to regex ciąg byłby lepszy: "\r?\n".
Rory O'Kane,
7
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 stringobiekt, 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{publicstaticclassStringExtensions{publicstaticstring[]Split(thisstring s,string delimiter,StringSplitOptions options =StringSplitOptions.None){return s.Split(newstring[]{ 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 onlystring 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.NewlineKorzystne jest trudne kodowania albo \nczy \r\n.
Michael Blackburn
3
@MichaelBlackburn - To nieprawidłowe stwierdzenie, ponieważ nie ma kontekstu. Environment.Newlinejest 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.Newlinegwarantuje, że nie ma spójności w typie powrotu linii między systemami operacyjnymi, gdzie „kodowanie na stałe” daje programistom pełną kontrolę.
Kraang Prime
2
@MichaelBlackburn - Nie musisz być niegrzeczny. Po prostu podawałem informacje. .Newlinenie 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 .Newlineoznacza 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.
Kraang Prime
To, co słyszę, jest najbardziej czytelnym sposobem (być może wyższym wykorzystaniem pamięci) foo = foo.Replace("\r\n", "\n"); string[] result = foo.Split('\n');. Czy rozumiem poprawnie, że działa to na wszystkich platformach?
John Doe
4
Obecnie używam tej funkcji (na podstawie innych odpowiedzi) w VB.NET:
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 Publici przeniosę do klasy użyteczności, a może nawet uczynię to metodą rozszerzenia.
@Samuel - zwróć uwagę na cytaty. W rzeczywistości mają to znaczenie. "\r"= powrót. "\r\n"= powrót + nowa linia. (proszę przejrzeć ten post i zaakceptowane rozwiązanie tutaj
Kraang Prime
@Kraang Hmm .. Dawno nie pracowałem z .NET. Byłbym zaskoczony, gdyby tylu ludzi głosowało złą odpowiedź. Widzę, że skomentowałem odpowiedź Guffy i otrzymałem tam wyjaśnienie. Usunąłem swój komentarz do tej odpowiedzi. Dzięki za heads-upy.
Samuel
2
Właściwie podział powinien zrobić:
//Constructing string...StringBuilder sb =newStringBuilder();
sb.AppendLine("first line");
sb.AppendLine("second line");
sb.AppendLine("third line");string s = sb.ToString();Console.WriteLine(s);//Splitting multiline string into separate linesstring[] splitted = s.Split(newstring[]{System.Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);// Output (separate lines)for(int i =0; i < splitted.Count(); i++){Console.WriteLine("{0}: {1}", i, splitted[i]);}
Opcja RemoveEmptyEntries usunie puste wiersze z tekstu. Może to być pożądane w niektórych sytuacjach, ale zwykły podział powinien zachować puste linie.
Guffa,
tak, masz rację, właśnie założyłem, że ... no cóż, puste linie nie są interesujące;)
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.
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.
Unikaj 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 pathto C:\Temp\test.txtnależy wtedy string[] lines = File.ReadLines(path);.
vapcguy
1
@vapcguy co właśnie przeczytałem? - Poleciłbym ponownie przeczytać post lub debugować go w programie konsoli, ponieważ wszystko, co powiedziałeś, jest po prostu złe | ścieżka jest ustawiona na Path.GetTempFileName | var jest powszechną i zalecaną definicją w języku C # - przy okazji definiuje typ zmiennej ...... EDYCJA: Nie twierdzę, że to dobre rozwiązanie
koanbock
@koanbock Ok, więc przejrzałem Path.GetTempFileNamemsdn.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.
vapcguy
-3
using System.IO;string textToSplit;if(textToSplit !=null){List<string> lines =newList<string>();
using (StringReader reader =newStringReader(textToSplit)){for(string line = reader.ReadLine(); line !=null; line = reader.ReadLine()){
lines.Add(line);}}}
Odpowiedzi:
Aby podzielić na ciąg, musisz użyć przeciążenia, które zajmuje tablicę ciągów:
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:
źródło
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
?źródło
while
pętlę, którą należy dodać do tej odpowiedzi.Powinieneś być w stanie dość łatwo rozdzielić łańcuch, na przykład:
źródło
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;
Umożliwi to wykonanie bardziej wydajnej pamięci wokół danych;
Oczywiście, jeśli chcesz mieć to wszystko w pamięci, możesz to zrobić;
źródło
blah.SplitToLines..
np.document.SplitToLines...
?this
parametry formalne, co czyni go metodą rozszerzenia.W oparciu o odpowiedź Guffy w klasie rozszerzającej użyj:
źródło
W przypadku zmiennej łańcuchowej
s
: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: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.źródło
Regex jest również opcją:
źródło
"\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.Możesz teraz użyć
.Split()
funkcji z dowolnego łańcucha w następujący sposób: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.
źródło
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 poleceniaEnvironment.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:
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:
źródło
"\r"
= powrót."\r\n"
= powrót + nowa linia. (proszę przejrzeć ten post i zaakceptowane rozwiązanie tutajWłaściwie podział powinien zrobić:
źródło
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.
źródło
Nie wiedziałem o Environment.Newline, ale myślę, że to bardzo dobre rozwiązanie.
Moja próba byłaby:
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.
źródło
Głupia odpowiedź: napisz do pliku tymczasowego, abyś mógł użyć czcigodnego
File.ReadLines
źródło
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, żepath
toC:\Temp\test.txt
należy wtedystring[] 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życiemvar
, ale powiedziałbym, że NIE jest to zalecane, ponieważ nie pokazuje, czym jest obiekt zmiennej. To zaciemnia to.źródło
Właściwie to bardzo łatwe.
VB.NET:
DO#:
źródło
Environment.NewLine
tak jak w VB.