#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()