Я пытаюсь сопоставить многострочный текст с помощью Java. Когда я использую Pattern
класс с Pattern.MULTILINE
модификатором, я могу соответствовать, но я не могу сделать это с(?m).
Тот же шаблон с (?m)
использованием и использованием String.matches
, похоже, не работает.
Я уверен, что что-то упустил, но понятия не имею, что. Я не очень хорош в регулярных выражениях.
Это то что я пробовал
String test = "User Comments: This is \t a\ta \n test \n\n message \n";
String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find()); //true
String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2)); //false - why?
(?s)User Comments:\s*(.*)
. Из ответа @Amarghosh я получил образецUser Comments: [\\s\\S]*
. Среди них есть лучший или рекомендуемый способ или это просто два разных способа сделать то же самое?[\s\S]
является немного более явным («соответствует любому символу, который является пробелом или не пробелом»),.
его легче читать, но вам нужно искать модификатор(?s)
илиDOTALL
, чтобы узнать, включены ли новые строки или нет. Я бы предпочел.
с установленнымPattern.DOTALL
флагом (это легче читать и запоминать, чем(?s)
на мой взгляд. Вы должны использовать то, что вам удобнее всего..*
сDOTALL
более читабельным. Я использовал другой, чтобы показать, что проблема заключается в различиях между str.matches и matcher.find, а не в флагах. +1.*
сPattern.DOTALL
, но придется идти с (? S), потому что я должен использоватьString.matches
.Это не имеет ничего общего с флагом MULTILINE; что вы видите , разница между
find()
иmatches()
методами.find()
успешен, если совпадение может быть найдено где-либо в целевой строке , в то времяmatches()
как регулярное выражение соответствует всей строке .Кроме того,
MULTILINE
это не значит, что вы думаете. Многие люди приходят к выводу, что вы должны использовать этот флаг, если ваша целевая строка содержит новые строки, то есть если она содержит несколько логических строк. Я видел несколько ответов на SO на этот счет, но на самом деле все, что делает флаг, это изменяет поведение якорей,^
и$
.Обычно
^
соответствует самому началу целевой строки и$
самому концу (или перед новой строкой в конце, но мы пока оставим это в стороне). Но если строка содержит символы новой строки, вы можете выбрать^
и$
сопоставлять начало и конец любой логической строки, а не только начало и конец всей строки, установив флаг MULTILINE.Так что забудьте о том, что
MULTILINE
значит, и просто вспомните, что он делает : меняет поведение^
и$
якоря.DOTALL
Режим первоначально назывался «однострочным» (и до сих пор присутствует в некоторых вариантах, включая Perl и .NET), и он всегда вызывал подобную путаницу. Нам повезло, что в этом случае разработчики Java получили более описательное имя, но разумной альтернативы для «многострочного» режима не было.В Perl, где все это безумие началось, они признали свою ошибку и избавились от «многострочных» и «однострочных» режимов в регулярных выражениях Perl 6. Через двадцать лет, возможно, весь остальной мир последует их примеру.
источник
str.matches(regex)
ведет себя так, как будтоPattern.matches(regex, str)
пытается сопоставить всю входную последовательность с шаблоном и возвращаетПринимая во внимание, что
matcher.find()
пытается найти следующую подпоследовательность входной последовательности, которая соответствует шаблону, и возвращаетТаким образом, проблема с регулярным выражением. Попробуйте следующее.
Таким образом, короче говоря,
(\\W)*(\\S)*
часть в вашем первом регулярном выражении соответствует пустой строке, что*
означает ноль или более вхождений, а реальная совпавшая строка - этоUser Comments:
не вся строка, как вы ожидаете. Второй сбой, поскольку он пытается сопоставить всю строку, но не может, поскольку\\W
совпадает с несловесным символом, т.е.[^a-zA-Z0-9_]
и первый символ являетсяT
символом слова.источник
User Comments: [\\s\\S]*
и это сработало. (спасибо!) Из ответа @Tim я получил образецUser Comments:(.*)
, это тоже нормально. Теперь, есть ли рекомендуемый или лучший способ среди них, или это всего лишь два способа сделать то же самое?(.*)
вместе сDOTALL
флагом это более очевидно / читабельно, чем([\\s\\S]*)
Многострочный флаг сообщает регулярному выражению, что шаблон должен соответствовать каждой строке, а не всей строке, для ваших целей подстановочный знак будет достаточным.
источник