Почему символ точки в regex не захватывает переносы строки?
Нередко в материалах по regex говорят, что спецсимвол точка . означает любой символ. Но это не так, точка обозначает любой символ кроме переноса строки.
Я получил из-за этого ошибку и вообще меня такой расклад удивил.
Допустим, я хочу сделать захват такого текста:
Шла Саша по шоссе
и сосала
сушку
Я бы сделал что-то подобное: \A.*\Z, вот только выясняется, что это не работает. Зато представленный выше текст можно захватить при помощи указания символов, которые не должны встречаться. Вот так например: \A[^%]*\Z
У меня два вопроса:
- Почему точка не обозначает перенос строки (в чём был смысл такого решения)?
- Как мне справиться с ситуацией, когда я хочу сделать захват вообще всего, что угодно, переносов строки в том числе?
Важное примечание: я знаю про существование этого вопроса. Но во-первых я хочу понять, почему вообще так исторически сложилось, что точка не захватывает перенос строки. А во-вторых меня интересует решение проблемы в контексте java.
Ответы (1 шт):
Чтобы точка соответствовала любому символу, включая перенос строки, необходимо включить режим Pattern.DOTALL.
Например, этот код захватит целиком весь текст, вместе с переносами строк:
Pattern pattern = Pattern.compile(".*", Pattern.DOTALL);
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println(matcher.group());
}
Этот режим можно включить и другим способом, добавить флаг ?s непосредственно в регулярное выражение.
Например, для многострочного текста здесь мы получим true:
System.out.println(text.matches("(?s).*"));
Какие еще бывают флаги можно посмотреть в официальном туториале.
Исторически так сложилось из-за того, что первые инструменты, которые использовали регулярные выражения, обрабатывали тексты построчно. Поэтому, предполагалось, что переноса строки в тексте быть не должно.
Концепт регулярных выражений появился в 1950-х годах. Регулярки широко использовались вместе с юниксовыми текстовыми утилитами. Если вам приходилось иметь дело с командной строкой linux, то вы могли видеть, как работать с текстом с помощью grep, sed, awk и perl: большинство команд применяются к тексту строчка за строчкой.