.NET Regex dot character соответствует возврату каретки?
Каждый единственный аромат регулярного выражения, который я когда-либо использовал, всегда имел ".". символ соответствует всем, кроме новой строки (\ r или \n)... если, конечно, вы не включите однострочный флаг.
Итак, когда я попробовал следующий код на С#, я был в шоке:
Regex rgx = new Regex(".");
if (rgx.Match("\r\n").Success)
MessageBox.Show("There is something rotten in the state of Redmond!");
Он показал сообщение. Чтобы убедиться, что я не схожу с ума, я попробовал следующий код JavaScript:
if (/./.test("\r\n"))
alert("Something wrong with JavaScript too.");
В JavaScript не было показано сообщение, что означает, что он работает точно так, как должен.
По-видимому, "." символ в .NET соответствует символу "\ r". Я проверил документацию, чтобы узнать, есть ли упоминание об этом:
Подстановочный знак: соответствует любому одиночному символу кроме \n.
Ух ты... с каких пор аромат регулярного выражения когда-либо совпал с точкой возврата каретки? Вы могли бы подумать, что .NET будет вести себя как все остальные варианты Regex... особенно потому, что это в среде Windows, которая использует "\ r\n" в качестве разделителей строк.
Есть ли какой-либо флаг/параметр, который я могу включить, чтобы он работал так же, как и в других вариантах Regex? Существуют ли альтернативные решения, которые не включают замену всех символов .
на [^\r\n]
?
Ответы
Ответ 1
Я столкнулся с этой проблемой при написании Regex Hero. Это немного странно. Я писал о проблеме здесь. И это привело к добавлению функции тестеру для включения/отключения CRLF. Во всяком случае, по какой-то причине Microsoft решила использовать \n (линейные каналы) для отметки окончаний строки.
(ОБНОВЛЕНИЕ) Причина должна быть связана с этим:
Microsoft.NET Framework выражения включают наиболее популярные функции других регулярных реализации выражений, таких как в Perl и awk. Предназначен для совместимый с Perl 5 выражения, регулярный .NET Framework выражения включают еще функции в других реализациях, таких как совпадение справа налево и на лету сборник. http://msdn.microsoft.com/en-us/library/hs600312.aspx
И как отметил Игорь, Perl имеет такое же поведение.
Теперь Singleline и Multiline RegexOptions изменяют поведение, основанное на точках и линиях. Вы можете включить Singleline RegexOption, чтобы точка соответствовала строкам строк. И вы можете включить Multiline RegexOption так, чтобы ^ и $отмечали начало и конец каждой строки (обозначается линейными фидами). Но вы не можете изменить присущее поведение оператора точки (.) Для соответствия всем, кроме\r\n.
Ответ 2
Я думаю, что точка здесь состоит в том, что точка должна соответствовать всем, что не является разделителем строк, а \r
- разделителем строк. Perl уходит с распознаванием только \n
, потому что он (как указывали другие) указывает на мир Unix и потому что он вдохновляет ароматы регулярных выражений, встречающиеся на большинстве других языков.
(Но я отмечаю, что в Perl 6 regexes (или Rules, для использования их формального имени) /\n/
соответствует любому, что распознано Unicode как разделитель строк, включая оба символа последовательности \r\n
.)
.NET родился в эпоху Unicode; он должен распознавать все разделители строк, поддерживаемые Unicode, включая \r
(старый стиль Mac) и \r\n
(который используется некоторыми сетевыми протоколами, а также Windows). Рассмотрим этот пример в Java:
String s = "fee\nfie\r\nfoe\rfum";
Pattern p = Pattern.compile("(?m)^.+$");
Matcher m = p.matcher(s);
while (m.find())
{
System.out.println(m.group().length());
}
результат:
3
3
3
3
.
, ^
и $
все работают правильно со всеми тремя разделителями строк. Теперь попробуйте в С#:
string s = "fee\nfie\r\nfoe\rfum";
Regex r = new Regex(@"(?m)^.+$");
foreach (Match m in r.Matches(s))
{
Console.WriteLine(m.Value.Length);
}
результат:
3
4
7
Это похоже на кого-то другого? Здесь у нас есть аромат регулярных выражений, встроенный в платформу Microsoft.NET, и он даже не обрабатывает стандартный разделитель строк Windows. И он полностью игнорирует одиночный \r
, так же как и другие разделители строк Unicode..NET появился через несколько лет после Java, и его поддержка Unicode по крайней мере так же хороша, так почему они решили придерживаться этой точки?
Ответ 3
За исключением режима SingleLine, .
будет соответствовать любому символу, кроме \n
.
Как вы заметили, оно соответствует \r
.
Я не знаю почему.
Ответ 4
Регулярные выражения имеют практическое (в противоположность теоретическому) происхождение в среде Unix, где LF является терминатором линии, тогда он кажется полностью подходящим. чтобы соответствовать всем, кроме LF.
Это односимвольное совпадение, поэтому сопоставление CRLF было бы слишком большим, чтобы спросить, и соответствие CR или LF может вызвать проблемы с переходом на другую платформу regex. Я думаю, использование \s было бы лучшим подходом для сопоставления белого пространства и будет соответствовать как CR, так и LF.
Ответ 5
Ну, я не думаю, что "в состоянии Редмонда есть что-то гнилое!", по крайней мере, ваш сценарий не является доказательством этого. Но я думаю, что это поведение не ошибка, а скорее функция. Зачем? Просто потому, что регулярные выражения Perl имеют такое же поведение (я только что проверил его), и я считаю, что PHP PCRE (Perl Compatible Regular Expressions) ведут себя одинаково. И MS просто заставляли их методы Regex вести себя так же, как де-факто классические Perl. И теперь мой вопрос: "Что случилось в царстве JS?":)