Регулярное выражение Java всегда завершается ошибкой

#java #regex #unicode

#java #регулярное выражение #unicode

Вопрос:

У меня есть шаблон регулярных выражений Java и предложение, которому я хотел бы полностью соответствовать, но для некоторых предложений он ошибочно завершается ошибкой. Почему это? (для простоты я не буду использовать свое сложное регулярное выражение, а просто «.*»)

 System.out.println(Pattern.matches(".*", "asdf"));
System.out.println(Pattern.matches(".*", "[11:04:34] <@Aimbotter> 1 more thing"));
System.out.println(Pattern.matches(".*", "[11:04:35] <@Aimbotter> Dialogue: 0,0:00:00.00,0:00:00.00,Default,{Orginal LV,0000,0000,0000,,[???]??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????} "));
System.out.println(Pattern.matches(".*", "[11:04:35] <@Aimbotter> Dialogue: 0,0:00:00.00,0:00:00.00,Default,{Orginal LV,0000,0000,0000,,[???]????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????} "));
  

Вывод:

 true
true
true
false
  

Обратите внимание, что четвертое предложение содержит 10 управляющих символов Unicode u0085 между вопросительными знаками, которые не отображаются обычными шрифтами. Третье и четвертое предложения на самом деле содержат одинаковое количество символов!

Комментарии:

1. Это особенно странно, потому что Java — это движок регулярных выражений в Юникоде…

2. Было бы хуже, если бы Java не знала о терминаторах строки Unicode ( fileformat.info/info/unicode/char/85/index.htm )

3. … @tchrist скоро будет рядом и расскажет нам все о том, насколько сломан движок регулярных выражений java.

Ответ №1:

используйте

 Pattern.compile(".*",Pattern.DOTALL)
  

если вы хотите. для сопоставления управляющих символов. По умолчанию оно соответствует только печатным символам.

Из JavaDoc:

«В режиме dotall выражение . соответствует любому символу, включая символ завершения строки. По умолчанию это выражение не соответствует терминаторам строки.

Режим Dotall также может быть включен с помощью встроенного выражения флага (? выражений). (s — это мнемоника для режима «однострочный», как это называется в Perl.)»

Код в шаблоне (есть ваш u0085):

 /**
 * Implements the Unicode category ALL and the dot metacharacter when
 * in dotall mode.
 */
static final class All extends CharProperty {
boolean isSatisfiedBy(int ch) {
    return true;
}
}

/**
 * Node class for the dot metacharacter when dotall is not enabled.
 */
static final class Dot extends CharProperty {
boolean isSatisfiedBy(int ch) {
    return (ch != 'n' amp;amp; ch != 'r'
                amp;amp; (ch|1) != 'u2029'
                amp;amp; ch != 'u0085');
    }
}
  

Комментарии:

1. Спасибо, (? s) сработало. Я не пробовал шаблон. DOTALL, потому что у меня есть тонна разных скомпилированных шаблонов, и мне пришлось использовать (? s) только один раз (в строковой константе, которую я включаю в большинство шаблонов).

Ответ №2:

Ответ содержится в вопросе: 10 управляющих символов Unicode u0085

управляющие символы Unicode не распознаются .* точно так же, как n

Ответ №3:

Unicode / u0085 — это новая строка, поэтому вам нужно либо добавить (?s) — совпадение точек со всеми — в начало вашего регулярного выражения, либо добавить флаг при компиляции регулярного выражения.

 Pattern.matches("(?s).*", "blahDeBlahu0085Blah")
  

Комментарии:

1. Не (?m) Многострочный режим означает, что ^ и $ совпадают в начале / конце строк. Вы хотите (?s) использовать однострочный режим. Да, это сбивает с толку (идея состоит в том, чтобы «обрабатывать весь ввод, как если бы это была одна строка»).

Ответ №4:

Проблема, я полагаю, в том, что u0085 представляет новую строку. Если вы хотите многострочное сопоставление, вам нужно использовать шаблон.МНОГОСТРОЧНЫЙ или шаблон.DOTALL. Не факт, что это Юникод — ‘ n’ тоже потерпит неудачу.

Чтобы использовать его: Pattern.compile(regex, Pattern.DOTALL).matcher(input).matches()