2009-05-08 10 views
36

Jak normalizować wszystkie sekwencje nowej linii w ciągu do jednego typu?Jaki jest szybki sposób wymuszenia CRLF w C#/.NET?

Szukam ich wszystkich CRLF do celów e-mail (dokumenty MIME). Idealnie byłoby zawinięte w statyczną metodę, wykonującą bardzo szybko i nie używając wyrażeń regularnych (ponieważ wariancje podziałów linii, powroty karetki itp. Są ograniczone). Być może jest nawet metoda BCL, którą przeoczyłem?

Wniebowzięcie: Po rozważeniu tego, myślę, że to bezpieczne założenie, aby powiedzieć, że CR są albo autonomiczne, albo część sekwencji CRLF. Oznacza to, że jeśli widzisz CRLF, wiesz, że wszystkie CR można usunąć. W przeciwnym razie trudno powiedzieć, ile linii powinno wyjść z czegoś w rodzaju "\ r \ n \ n \ r".

Odpowiedz

52
input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n") 

To będzie działać, jeśli wejście zawiera tylko jeden rodzaj przerwy Line - albo CR lub LF lub CR + LF.

+0

Działa również w celu wyświetlania nieznanego tekstu na stronie HTML za pomocą ostatniego zamiennika, aby wstawić znacznik BR. Server.HtmlEncode (wejście) .Zmień ("\ r \ n", "\ n"). Zamień ("\ r", "\ n"). Zamień ("\ n", "
"); –

+0

To szwy, aby rozwiązać problemy z szablonami T4.Ciągle uzyskiwałam zwariowane zyski w generowanych wynikach. – DaImTo

4
string nonNormalized = "\r\n\n\r"; 

string normalized = nonNormalized.Replace("\r", "\n").Replace("\n", "\r\n"); 
+1

Ten przykład tworzy cztery linie podziału, podczas gdy niezormowany łańcuch zawiera dwa. –

+0

To prawda, że ​​pojawia się dobre pytanie, kiedy sekwencja jest używana i kiedy jest po prostu usunięta (zignorowana). –

28

To zależy od wymagań, jakie należy spełnić podając . W szczególności, jak chcesz obsłużyć "\ r" na własną rękę? Czy to się liczy jako przerwa w linii, czy nie? Jako przykład, jak należy traktować "a \ n \ rb"? Czy to jest jedna bardzo dziwna przerwa między wierszami, jedna "\ n" przerwa, a następnie nieuczciwość "\ r", czy dwa oddzielne podziały wiersza? Jeśli "\ r" i "\ n" mogą być samodzielne, to dlaczego "\ r \ n" nie powinno być traktowane jako dwa linebreaki?

Oto kod, który, jak podejrzewam, jest sprawny pod względem skuteczności .

using System; 
using System.Text; 

class LineBreaks 
{  
    static void Main() 
    { 
     Test("a\nb"); 
     Test("a\nb\r\nc"); 
     Test("a\r\nb\r\nc"); 
     Test("a\rb\nc"); 
     Test("a\r"); 
     Test("a\n"); 
     Test("a\r\n"); 
    } 

    static void Test(string input) 
    { 
     string normalized = NormalizeLineBreaks(input); 
     string debug = normalized.Replace("\r", "\\r") 
           .Replace("\n", "\\n"); 
     Console.WriteLine(debug); 
    } 

    static string NormalizeLineBreaks(string input) 
    { 
     // Allow 10% as a rough guess of how much the string may grow. 
     // If we're wrong we'll either waste space or have extra copies - 
     // it will still work 
     StringBuilder builder = new StringBuilder((int) (input.Length * 1.1)); 

     bool lastWasCR = false; 

     foreach (char c in input) 
     { 
      if (lastWasCR) 
      { 
       lastWasCR = false; 
       if (c == '\n') 
       { 
        continue; // Already written \r\n 
       } 
      } 
      switch (c) 
      { 
       case '\r': 
        builder.Append("\r\n"); 
        lastWasCR = true; 
        break; 
       case '\n': 
        builder.Append("\r\n"); 
        break; 
       default: 
        builder.Append(c); 
        break; 
      } 
     } 
     return builder.ToString(); 
    } 
} 
+0

Bardzo fajnie; byłoby to z pewnością użyteczne przy bardziej arbitralnym wprowadzaniu! W moim przypadku zdecydowałem się na założenie (dokonałem edycji), ale głosowałem niezależnie od tego. –

+0

Dobrze. Jeśli wydajność jest naprawdę znacząca, możesz chcieć porównać to rozwiązanie z zaakceptowanym - ale tylko wtedy, gdy upewnisz się, że jest to znaczące dzięki profilerowi! Chciałbym * mieć nadzieję *, że jest to szybsze, ponieważ wystarczy wykonać pojedyncze przejście przez dane. –

+0

Co jest o użyciu RegExpr? nie dobra wydajność? http://stackoverflow.com/questions/140926/normalize-newlines-in-c-sharp – Kiquenet

3

Prosty wariant:

Regex.Replace(input, @"\r\n|\r|\n", "\r\n") 

Dla lepszej wydajności:

static Regex newline_pattern = new Regex(@"\r\n|\r|\n", RegexOptions.Compiled); 
[...] 
    newline_pattern.Replace(input, "\r\n"); 
0

Jest to szybki sposób to zrobić, mam na myśli.

Nie używa drogiej funkcji regularnego wyliczania. Nie korzysta z wielu funkcji wymiany, z których każda wykonywała pętlę nad danymi z kilkoma kontrolami, przydziałami itp.

Wyszukiwanie odbywa się bezpośrednio w pętli 1 dla. Aby liczba operacji zwiększania pojemności tablicy wyników była większa, w ramach funkcji Array.Copy używana jest również pętla. To są wszystkie pętle. W niektórych przypadkach większy rozmiar strony może być bardziej wydajny.

public static string NormalizeNewLine(this string val) { 
    if (string.IsNullOrWhiteSpace(val)) 
     return val; 

    const int page = 6; 
    int a = page; 
    int j = 0; 
    int len = val.Length; 
    char[] res = new char[len]; 
    for (int i = 0; i < len; i++) { 
     char ch = val[i]; 
     if (ch == '\r') { 
      int ni = i + 1; 
      if (ni < len && val[ni] == '\n') { 
       res[j++] = '\r'; 
       res[j++] = '\n'; 
       i++; 
      } else { 
       if (a == page) { //ensure capacity 
        char[] nres = new char[res.Length + page]; 
        Array.Copy(res, 0, nres, 0, res.Length); 
        res = nres; 
        a = 0; 
       } 
       res[j++] = '\r'; 
       res[j++] = '\n'; 
       a++; 
      } 
     } 
     else if (ch == '\n') { 
      int ni = i + 1; 
      if (ni < len && val[ni] == '\r') { 
       res[j++] = '\r'; 
       res[j++] = '\n'; 
       i++; 
      } else { 
       if (a == page) { //ensure capacity 
        char[] nres = new char[res.Length + page]; 
        Array.Copy(res, 0, nres, 0, res.Length); 
        res = nres; 
        a = 0; 
       } 
       res[j++] = '\r'; 
       res[j++] = '\n'; 
       a++; 
      } 
     } else { 
      res[j++] = ch; 
     } 
    } 
    return new string(res, 0, j); 
} 

Teraz "\ n \ r" nie jest używane na podstawowych platformach. ale: kto użyłby dwóch typów linii po kolei, aby wskazać 2 linie podziału? Jeśli chcesz to wiedzieć, musisz najpierw sprawdzić, czy \ n i \ r są używane osobno w tym samym dokumencie.

Powiązane problemy