Регулярное выражение не соответствует пустой строке в многострочном режиме (Java) - PullRequest
14 голосов
/ 17 января 2012

Я только что заметил это поведение;

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 */

Так что это? Как я понимаю это? Я надеюсь, что кто-то может пролить свет на это, будет очень признателен.

Ответы [ 3 ]

7 голосов
/ 17 января 2012

Если активирован режим MULTILINE, то ^ совпадает в начале ввода и после любого конца строки, кроме конца ввода.

Поскольку вы находитесь в конце ввода, ^ не может совпадать в многострочном режиме.

Это удивительно, даже отвратительно, но, тем не менее, согласно документации.

2 голосов
/ 17 января 2012

Давайте посмотрим немного ближе на ваш второй пример:

Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE);
Matcher m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */

Таким образом, у вас есть строка в м2, которая является пустой ИЛИ содержит только символ конца строки и никаких других символов. Поэтому ваш шаблон, чтобы соответствовать данной строке, должен быть только «$», т.е.

// Your example
Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE);
Matcher m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */

// Let's check if it is start of the line
p2 = Pattern.compile("^", Pattern.MULTILINE);
m2 = p2.matcher("");
System.out.println(m2.matches()); /* false */

// Let's check if it is end of the line
p2 = Pattern.compile("$", Pattern.MULTILINE);
m2 = p2.matcher("");
System.out.println(m2.matches()); /* true */
1 голос
/ 17 января 2012

Звучит как ошибка.Самое большее, в многострочном режиме, «^» и «$» можно интерпретировать как сопоставление на внутренней границе линии.В 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...