Регулярное выражение не соответствует пустой строке в многострочном режиме (Java)
Я только что наблюдал это поведение;
Pattern p1 = Pattern.compile("^$");
Matcher m1 = p1.matcher("");
System.out.println(m1.matches()); /* true */
Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE);
Matcher m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */
Мне кажется странным, что последнее утверждение ложно. Это то, что говорят документы;
По умолчанию регулярные выражения ^ и $игнорируют линейные терминаторы и соответствуют только в начале и в конце всей входной последовательности. Если режим MULTILINE активирован, то ^ совпадает в начале ввода и после любого терминатора линии, кроме как в конце ввода. Когда в режиме MULTILINE $совпадает только перед терминатором линии или концом входной последовательности. http://docs.oracle.com/javase/1.4.2...
Из чего я получаю от этого, он должен соответствовать? Следующее делает вещи еще более запутанными;
Pattern p3 = Pattern.compile("^test$");
Matcher m3 = p3.matcher("test");
System.out.println(m3.matches()); /* true */
Pattern p4 = Pattern.compile("^test$", Pattern.MULTILINE);
Matcher m4 = p4.matcher("test");
System.out.println(m4.matches()); /* true */
Так что это? Как я могу это понять? Я надеюсь, что кто-то может пролить свет на это, будет очень благодарен.
Ответы
Ответ 1
Если режим MULTILINE активирован, то ^ совпадает в начале вход и после любого терминатора линии, кроме как в конце ввода.
Поскольку вы находитесь в конце ввода, ^
не может совпадать в многострочном режиме.
Это удивительно, даже отвратительно, но, тем не менее, согласно его документации.
Ответ 2
Давайте посмотрим немного ближе к вашему второму примеру:
Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE);
Matcher m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */
Итак, у вас есть строка в m2, которая пуста OR, содержит только символ конечной линии и других символов. Поэтому шаблон, чтобы соответствовать данной строке, должен быть только "$" i.e.:
// Your example
Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE);
Matcher m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */
// Let check if it is start of the line
p2 = Pattern.compile("^", Pattern.MULTILINE);
m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */
// Let check if it is end of the line
p2 = Pattern.compile("$", Pattern.MULTILINE);
m2 = p2.matcher("");
System.out.println(m2.matches()); /* true */
Ответ 3
Звучит как ошибка. Максимум, в многострочном режиме, "^" и "$" можно интерпретировать как совпадение на внутренней границе линии. Возможно, Java не имеет расширенной структуры переменных состояний, как это делает Perl. Я не знаю, является ли это даже причиной.
Тот факт, что /^test$/m
соответствует только доказать, что функция $$ работает в многострочном режиме, за исключением случаев, когда строка пуста (на Java), но явно многострочный тест для пустой строки является смехотворным, поскольку /^$/
работает для этого.
Тестирование в Perl, все работает так, как ожидалось:
if ( "" =~ /^$/m ) { print "/^\$/m matches\n"; }
if ( "" =~ /^$/ ) { print "/^\$/ matches\n"; }
if ( "" =~ /\A\Z/m ) { print "/\\A\\Z/m matches\n"; }
if ( "" =~ /\A\Z/ ) { print "/\\A\\Z/ matches\n"; }
if ( "" =~ /\A\z/ ) { print "/\\A\\z/ matches\n"; }
if ( "" =~ /^/m ) { print "/^/m matches\n"; }
if ( "" =~ /$/m ) { print "/\$/m matches\n"; }
__END__
/^$/m matches
/^$/ matches
/\A\Z/m matches
/\A\Z/ matches
/\A\z/ matches
/^/m matches
/$/m matches