2009-06-12 22 views
5

Dlaczego .NET regex nie traktuje \ n jako znaku końca linii?. Klasa Regex i nowa linia .NET:

Przykładowy kod:

string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" }; 
Regex regex = new Regex("^[a-z0-9]+$"); 
foreach (var word in words) 
{ 
    Console.WriteLine("{0} - {1}", word, regex.IsMatch(word)); 
} 

I to jest odpowiedź uzyskać:

ab1 - True 
ab2 
- True 
ab3 

- False 
- False 
ab5 
- False 
ab6 
- False 

Dlaczego mecz regex ab2\n?

Aktualizacja: Nie sądzę Multiline jest dobrym rozwiązaniem, to znaczy chcę, aby potwierdzić logowanie pasujące tylko określonych znaków i musi być pojedyncza linia. Jeśli zmienię konstruktor dla opcji MultiLine ab1, ab2, ab3 i ab6 pasują do wyrażenia, ab4 i ab5 nie pasują do tego.

+0

Dlaczego nie AB4 pojawiają się na wyjściu? –

+0

Przypuszczam, że dzieje się tak z powodu samego \ r - to dokładne wyjście z konsoli – empi

Odpowiedz

9

Jeśli ciąg kończy się zerwaniem linii, RegexOptions.Multiline nie będzie działać. $ po prostu zignoruje ostatnią linię podziału, ponieważ nie ma nic po tym.

Jeśli chcesz dopasować do samego końca łańcucha i zignorować wszelkie podziały wiersza używać \z

Regex regex = new Regex(@"^[a-z0-9]+\z", RegexOptions.Multiline); 

Jest to zarówno MutliLine i SingleLine, że nie ma znaczenia.

+0

Smazy, masz rację. Zapomniałem o metaznakach \ Z \ z (+1) –

+0

To działa, ale czy wiesz, czy to podejście może spowodować inne problemy? Jaka jest różnica między \ z i $? – empi

+0

\ z dopasowuje tylko koniec ciągu, niezależnie od znaków nowej linii. –

1

Od RegexOptions:

trybu wielowierszowego. Zmienia znaczenie^i $, aby pasowały odpowiednio na początku i na końcu dowolnej linii, a nie tylko na początku i końcu całego łańcucha.

Więc w zasadzie, jeśli zdać RegexOptions.Multiline do konstruktora Regex jesteś pouczając, że wystąpienie w leczeniu ostateczną $ jako dopasowanie dla znaków nowej linii - a nie po prostu koniec samego łańcucha.

+0

O ile rozumiem, określam wszystkie znaki, które mogą pojawić się w ciągu znaków, a te znaki są znakami w zakresie [a-z0-9 ]. Nie zezwalam na \ n pojawianie się w łańcuchu, jednak wyrażenie regularne dopasowuje ciąg znaków do \ n. Nie rozumiem, co ma z tym wspólnego MultiLine. – empi

0

Mogą to być linie okienne/linuksowe kończące się różnicami ususal. Ale nadal jest dziwne, że \n\n dostaje fałszywy w ten sposób ... Czy próbowałeś z zestawem flag RegexOptions.Multiline?

0

Wystarczy podać więcej informacji na odpowiedź Smazy. To wyciąg z: Książka kucharska "Wyrażenia regularne" Jana Goyvaertsa i Stevena Levithana. Copyright 2009 Jan Goyvaerts i Steven Levithan, 978-0-596-2068-7

Różnica między <\ Z> i <\ oo> wchodzi w grę, gdy ostatni znaków w tekście jest przedmiotem a linia podziału . W takim przypadku <\ Z> może dopasować na samym końcu tekstu tematu , po ostatniej linii podziału, jako oraz bezpośrednio przed tą linią zerwania. Zaletą jest to, że możesz wyszukać bez konieczności martwienia się o koniec linii na końcu tekstu tematu .Podczas odczytywania wiersza pliku przez linię niektóre narzędzia zawierają linię na końcu linii , natomiast inne nie; <\ Z> zamaskowuje różnicę . <\ Z> dopasowuje tylko na samym końcu tekstu tematu, więc nie będzie pasować do tekstu, jeśli nastąpi następująca linia końcowa: . Kotwica <$> jest równa równoważna <\ Z>, dopóki nie wykonasz nie włączaj opcji "^ i $ przy linii zrywa". Ta opcja jest domyślnie wyłączona przez dla wszystkich smaków regex z wyjątkiem Ruby. Ruby nie oferuje sposobu na wyłączenie tej opcji za pomocą . Podobnie jak <\ Z>, <$> pasuje na samym końcu tekstu tematu, a także przed ostateczną wersją linii , jeśli taka istnieje.

Oczywiście, nie znalazłbym go bez odpowiedzi Smazy.

10

Silnik regex .NET traktuje \n jako koniec linii. I to jest problem, jeśli twój ciąg znaków ma przerwę w stylu w stylu Windows \r\n. Z RegexOptions.Multiline włączyła $ mecze pomiędzy \r i \n, a nie przed \r.

$ również pasuje na samym końcu łańcucha, podobnie jak \z. Różnica polega na tym, że \z można dopasować tylko na samym końcu ciągu, podczas gdy $ również pasuje przed końcowym \n. Podczas korzystania z RegexOptions.Multiline, $ pasuje również przed dowolnym \n.

Jeśli masz problemy z podziałem wierszy, wystarczy najpierw przetestować i zastąpić, aby zastąpić wszystkie \r bez niczego, aby upewnić się, że wszystkie linie kończą się tylko z \n.

+2

Wolę zastępowanie "\ r \ n" przez "\ n", na wypadek gdyby jakiś zwariowany dokument miał tylko "\ r" jako końcowy wiersz. – Jimmy

1

Korzystanie z opcji regex, System.Text.RegularExpressions.RegexOptions:

string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" }; 
Regex regex = new Regex("^[a-z0-9]+$"); 
foreach (var word in words) 
{ 
    Console.WriteLine("{0} - {1}", word, 
     regex.IsMatch(word,"^[a-z0-9]+$", 
      System.Text.RegularExpressions.RegexOptions.Singleline | 
      System.Text.RegularExpressions.RegexOptions.IgnoreCase | 
      System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace)); 
}