.NET'te yeni satırlara bir dize bölmenin en kolay yolu?


806

Ben .NET'te yeni satırlara bir dize bölmek ve dizeleri bölmek için bildiğim tek yolu Split yöntemidir. Ancak bu, yeni bir satıra (kolayca) ayrılmama izin vermeyecek, bunu yapmanın en iyi yolu nedir?


2
Neden olmasın? Sadece System.Environment.NewLine üzerinde bölünmüş
aviraldg

16
Ama bunu bir dizgiye [] sarmalı ve fazladan bir argüman eklemelisin ve ... sadece tıknaz hissettiriyor.
RCIX

Yanıtlar:


1413

Bir dizeyi bölmek için bir dizi dizeyi alan aşırı yükü kullanmanız gerekir:

string[] lines = theText.Split(
    new[] { Environment.NewLine },
    StringSplitOptions.None
);

Düzenleme:
Bir metinde farklı satır sonları işlemek istiyorsanız, birden fazla dizeyi eşleme yeteneğini kullanabilirsiniz. Bu, her iki satır sonu türüne de doğru şekilde bölünecek ve metindeki boş satırları ve aralıkları koruyacaktır:

string[] lines = theText.Split(
    new[] { "\r\n", "\r", "\n" },
    StringSplitOptions.None
);

3
@RCIX: Yönteme doğru parametreleri göndermek biraz gariptir, çünkü bunu yapabildiğinden çok daha basit bir şey için kullanıyorsunuz. En azından orada, çerçeve 2'den önce düzenli bir ifade kullanmanız ya da bir
ipte

4
@Leandro: Environment.NewLineÖzellik, sistem için varsayılan yeni satırı içerir. Örneğin bir Windows sistemi için "\r\n".
Guffa

3
@Leandro: Bir tahmin, programın her satırın sonunda \nbir bırakarak ayrılması ve \rardından \r\naralarında bir ile çıktılar üretmesi olacaktır .
Guffa

3
@Samuel: ( \rve \ndiğerleri arasında) ve kaçış dizilerinin C # derleyicisi için özel bir anlamı vardır. VB'de bu kaçış dizileri yoktur, bu nedenle bu sabitler kullanılır.
Guffa

2
Çeşitli işletim sistemlerinden çok sayıda dosyayı kabul etmek istiyorsanız, başlangıca "\ n \ r" ve sınırlayıcı listesinin sonuna "\ r" ekleyebilirsiniz. Performans isabetine değdiğinden emin değilim. ( en.wikipedia.org/wiki/Newline )
user420667

121

A kullanmaya ne dersiniz StringReader?

using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
    string line = reader.ReadLine();
}

13
Bu benim favorim. Bir uzatma yöntemine sarıldım
Ronnie Overby

3
Bu, .netcf 3.5
Carl

8
Giriş büyük olduğunda ve her şeyi bir diziye kopyalamak özellikle yavaş / bellek yoğun hale gelir.
Alejandro

1
Yazıldığı gibi, bu cevap sadece ilk satırı okur. Bu cevaba eklenmesi gereken döngü için Steve Cooper'ın cevabına bakınız while.
ToolmakerSteve

48

Dizenizi oldukça kolayca bölebilmelisiniz, şöyle:

aString.Split(Environment.NewLine.ToCharArray());

46
Newline dizesindeki ayrı karakterlere, yani CR ve LF karakterlerine bölünecek * nix olmayan bir sistemde. Bu, her satır arasında ekstra bir boş dizeye neden olur.
Guffa

Eğer yanılıyorsam beni düzeltin, ama bu \ ve n karakterlerinde bölünmez mi?
RCIX

7
@RCIX: Hayır, \ r ve \ n kodları tek karakterleri temsil eder. "\ R \ n" dizesi dört değil iki karakterdir.
Guffa

10
StringSplitOptions.RemoveEmptyEntries parametresini eklerseniz, bu mükemmel çalışır.
Ruben

18
@ Ruben: Hayır, olmayacak. Serge zaten cevabında bunu önerdi ve zaten orijinal metindeki korunması gereken boş satırları da kaldıracağını açıkladım.
Guffa

34

Genel bir çözüm için string.Split kullanmaktan kaçının, çünkü işlevi kullandığınız her yerde daha fazla bellek kullanırsınız - orijinal dize ve bölünmüş kopya, her ikisi de bellekte. Güvenmeye çalışın, ölçeklendirmeye başladığınızda bir sorun cehennemi olabilir - 100 MB'lık belgeleri işleyen 32 bit toplu işleme uygulaması çalıştırın ve eşzamanlı sekiz iş parçacığına bürüneceksiniz. Daha önce orada bulunduğumdan değil ...

Bunun yerine, böyle bir yineleyici kullanın;

    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;
            }
        }
    }

Bu, verileriniz çevresinde daha verimli bir bellek döngüsü gerçekleştirmenizi sağlar;

foreach(var line in document.SplitToLines()) 
{
    // one line at a time...
}

Tabii ki, eğer hepsini hafızada istiyorsanız, bunu yapabilirsiniz;

var allTheLines = document.SplitToLines.ToArray();

Ben orada bulundum ... (büyük HTML dosyaları ayrıştırma ve bellek yetersiz). Evet, dizeden kaçının. String.Split kullanmak Büyük Nesne Yığını (LOH) kullanımına neden olabilir - ama bundan% 100 emin değilim.
Peter Mortensen

SplitToLines statik bir yöntem (dd gibi görünüyorsa) yaptıysanız, nasıl blah.SplitToLines.. örn document.SplitToLines....
barlop

Görüyorum ki this, onu bir genişletme yöntemi haline getiren resmi parametreleri koyuyorsunuz .
barlop

26

Guffa'nın cevabına göre, bir uzantı sınıfında şunları kullanın:

public static string[] Lines(this string source) {
    return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}

9

Bir dize değişkeni için s:

s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)

Bu, ortamınızın satır sonları tanımını kullanır. Windows'ta satır sonları CR-LF (satır başı, satır besleme) veya C # 'ın çıkış karakteridir \r\n.

Bu güvenilir bir çözümdür, çünkü çizgileri yeniden birleştirirseniz String.Join, bu orijinal dizenize eşittir:

var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
var reconstituted = String.Join(Environment.NewLine,lines);
Debug.Assert(s==reconstituted);

Ne yapmamalı:

  • Kullanın StringSplitOptions.RemoveEmptyEntries, çünkü bu boş satırların sözdizimsel amaçlara sahip olduğu Markdown gibi işaretlemeyi kıracaktır.
  • Ayırıcıda bölün new char[]{Environment.NewLine}, çünkü Windows'ta bu her yeni satır için bir boş dize öğesi oluşturacaktır.

Temelde burada en çok puan alan, kabul edilenle aynı cevap, ama güzel bir birim testi ve uyarıları var.
vapcguy

8

Normal ifade de bir seçenektir:

    private string[] SplitStringByLineFeed(string inpString)
    {
        string[] locResult = Regex.Split(inpString, "[\r\n]+");
        return locResult;
    }

7
Eğer boş satırlar koruyarak tam satırları eşleştirmek istiyorsanız, bu düzenli ifade dize daha iyi olurdu: "\r?\n".
Rory O'Kane

7

Sadece iki bitimi ekleyeceğimi düşündüm, çünkü bu sorudaki diğer çözümler yeniden kullanılabilir kod sınıflandırmasına girmiyor ve uygun değil.

Aşağıdaki kod bloğu stringnesneyi, dizelerle çalışırken doğal bir yöntem olarak kullanılabilecek şekilde genişletir .

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);
        }
    }
}

Artık .Split()işlevi herhangi bir dizeden aşağıdaki gibi kullanabilirsiniz :

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);

Bir yeni satır karakterine bölünmek için, "\n"ya "\r\n"da ayırıcı parametresi olarak geçmeniz yeterlidir .

Yorum: Microsoft'un bu aşırı yüklemeyi uygulaması iyi olurdu.


Environment.Newlinesert kodlamaya ya \nda tercih edilir \r\n.
Michael Blackburn

3
@MichaelBlackburn - Bu geçersiz bir ifade çünkü bağlam yok. Environment.Newlineplatformlar arası uyumluluk içindir, geçerli işletim sisteminden farklı satır sonlandırmaları kullanan dosyalarla çalışmak için değildir. Daha fazla bilgi için buraya bakın , bu yüzden geliştiricinin neyle çalıştığına bağlı. 'İn kullanımı, Environment.Newline' sabit kodlamanın 'geliştiriciye tam denetim sağladığı işletim sistemleri arasında satır dönüş türünde tutarlılık olmamasını sağlar.
Kraang Prime

2
@MichaelBlackburn - Kaba olmanıza gerek yok. Sadece bilgi veriyordum. .Newlinesihir değil, kaputun altında sadece unix üzerinde mi yoksa pencerelerde mi çalıştığının bir anahtarına dayanarak yukarıda verilen dizeler. En güvenli bahis, önce tüm "\ r \ n" için bir dize değiştirme yapmak ve sonra "\ n" üzerine bölmektir. Kullanarak Nerede .Newlinebaşarısız satır sonları için farklı bir yöntem kullanan diğer programlar tarafından kaydedilen dosyaları ile çalışırken vardır. Dosyanın her zaman geçerli işletim sisteminizin satır sonlarını kullandığını biliyorsanız iyi çalışır.
Kraang Prime

Yani duyduğum en okunaklı yol (belki de daha yüksek bellek kullanımı) foo = foo.Replace("\r\n", "\n"); string[] result = foo.Split('\n');. Bunun tüm platformlarda çalıştığını doğru anlıyor muyum?
John Doe

4

Şu anda VB.NET bu işlevi (diğer yanıtlara dayalı) kullanıyorum:

Private Shared Function SplitLines(text As String) As String()
    Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
End Function

Önce platform-yerel satırsonuna bölünmeye çalışır ve sonra olası her satırsonuna geri döner.

Buna şimdiye kadar sadece bir sınıfta ihtiyacım vardı. Bu değişirse, muhtemelen bunu yapacağım Publicve bir yardımcı program sınıfına taşıyacağım ve hatta bir uzantı yöntemi bile yapacağım.

İyi bir önlem için hatlara nasıl katılacağınız aşağıda açıklanmıştır:

Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
    Return String.Join(Environment.NewLine, lines)
End Function

@Samuel - alıntılara dikkat edin. Aslında bu anlama geliyorlar. "\r"= dönüş. "\r\n"= dönüş + yeni satır. (Lütfen bu
gönderiyi

@Kraang Hmm .. .NET ile uzun zamandır çalışmadım. O kadar çok insan yanlış bir cevap vermişse şaşırırdım. Guffa'nın cevabına da yorum yaptığımı görüyorum ve orada açıklama aldım. Bu yanıta yaptığım yorumu sildim. Söylediğin için teşekkürler.
Samuel

2

Aslında bölünmüş yapmalı:

//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]);
}

2
RemoveEmptyEntries seçeneği metinden boş satırları kaldıracaktır. Bu bazı durumlarda arzu edilebilir, ancak düz bir çizgi boş satırları korumalıdır.
Guffa

evet, haklısın, ben sadece bu varsayımı yaptım, yani ... boş çizgiler ilginç değil;)
MaciekTalaska

1
string[] lines = text.Split(
  Environment.NewLine.ToCharArray(), 
  StringSplitOptions.RemoveEmptyStrings);

RemoveEmptyStrings seçenek, bir \ r aşağıdaki dolayı \ n boş girdileri yok emin olun

(Yorumları yansıtacak şekilde düzenleyin :) Metin içindeki orijinal boş satırları da sileceğini unutmayın. Bu genellikle istediğim şeydir, ancak gereksiniminiz olmayabilir.


RemoveEmptyStrings seçenekleri de boş satırları kaldıracağından metinde boş satırlar varsa düzgün çalışmaz.
Guffa

Muhtemelen orijinal boş satırları korumak istersiniz: \ r \ n \ r \ n
ince

0

Çevreyi bilmiyordum.Yeni, ama sanırım bu çok iyi bir çözüm.

Benim denemem şöyle olurdu:

        string str = "Test Me\r\nTest Me\nTest Me";
        var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();

Ek .Trim, hala mevcut olabilecek herhangi bir \ r veya \ n öğesini kaldırır (örneğin, pencerelerde iken, os x newline karakterleriyle bir dizeyi bölerek). Muhtemelen en hızlı yöntem olmasa da.

DÜZENLE:

Yorumların doğru bir şekilde işaret ettiği gibi, satırın başlangıcında veya yeni satır beslemesinden önceki boşlukları da kaldırır. Bu boşluğu korumanız gerekiyorsa, diğer seçeneklerden birini kullanın.


Kırpma ayrıca çizgilerin başında ve sonunda, örneğin girinti gibi beyaz boşlukları da kaldıracaktır.
Guffa

Msgstr ".Trim hala mevcut olabilecek herhangi bir \ r veya \ n öğesini kaldırır" - ah. Bunun yerine neden sağlam kod yazmıyorsunuz?
bzlm

Belki soruyu yanlış anladım, ancak boşlukların korunması gerektiği açıktı / belli değildi. Tabii ki haklısınız, Trim () boşlukları da siler.
Maksimum

1
@Max: Vay canına, patronuma kodun spesifikasyonda hariç tutulmayan herhangi bir şey yapmasına izin verildiğini söyleyene kadar bekleyin ...;)
Guffa

-2

Aptalca cevap: geçici bir dosyaya yazmak böylece saygıdeğer kullanabilirsiniz 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);

1
varDeğişken türünü tanımlamadığından kaçının , bu nedenle o nesneyi nasıl kullanacağınızı veya o nesnenin neyi temsil ettiğini anlamayabilirsiniz. Artı, bu satırları yazma gösterir ve bir dosya adı bile belirtmez, bu yüzden işe yarayacağından şüpheliyim. Daha sonra, okurken, dosyanın yolu tekrar belirtilmez. Varsayarsak pathise C:\Temp\test.txt, o zaman olmalıdır string[] lines = File.ReadLines(path);.
vapcguy

1
@vapcguy az önce ne okudum? - Gönderiyi tekrar okumanızı veya bir konsol programında hata ayıklamanızı öneririm çünkü söylediğiniz tek şey yanlıştır | yolu Path.GetTempFileName | var C # ortak ve önerilen bir tanımdır - bu arada bir değişkenin türünü tanımlamak ...... EDIT: Bunun iyi bir çözüm olduğunu söyleme
koanbock

@koanbock Tamam, bu yüzden Path.GetTempFileName msdn.microsoft.com/en-us/library/… ' ı aradım ve sıfır baytlık bir dosya oluşturduğunu ve "bu dosyanın tam yolunu" döndürdüğünü söylüyor . Yemin edebilirim daha önce denedim ve bir dosya bulamadığı için bir istisna verdi, ancak bunun yerine bir klasör konumu döndürüldü. Ben kullanmak için argüman biliyorum var, ama değişken nesnenin ne olduğunu göstermez çünkü tavsiye DEĞİL söyleyebilirim. O şaşırtıyor.
vapcguy

-3
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);
        }
    }
}

-5

Aslında çok kolay.

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);
}

4
Tamamen yanlış ve çalışmıyor. Artı, C # 'da, Environment.NewLinetıpkı VB'deki gibi.
vapcguy

Bkz . VB.NET'te Satır sonu tanımlayıcısı? yeni hat için farklı seçenekler.
Peter Mortensen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.