使用正则expression式匹配多行文本
我正在尝试使用java来匹配多行文本。 当我用Pattern.MULTILINE
修饰符使用Pattern
类时,我可以匹配,但是我不能用(?m).
与(?m)
和使用String.matches
相同的模式似乎不工作。
我确定我错过了什么,但不知道是什么。 对正则expression式不太擅长。
这是我的尝试
String test = "User Comments: This is \ta\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?
首先,你在一个不正确的假设下使用了修饰符。
Pattern.MULTILINE
或(?m)
告诉Java接受锚点^
和$
匹配每行的开始和结束(否则它们只匹配整个string的开始/结尾)。
Pattern.DOTALL
或(?s)
告诉Java允许点也匹配换行符。
其次,在你的情况下,正则expression式失败,因为你正在使用的matches()
方法,期望正则expression式匹配整个string – 这当然是行不通的,因为有一些字符后(\\W)*(\\S)*
已经匹配。
所以,如果你只是寻找一个string开始User Comments:
,使用正则expression式
^\s*User Comments:\s*(.*)
与Pattern.DOTALL
选项:
Pattern regex = Pattern.compile("^\\s*User Comments:\\s+(.*)", Pattern.DOTALL); Matcher regexMatcher = regex.matcher(subjectString); if (regexMatcher.find()) { ResultString = regexMatcher.group(1); }
然后, ResultString
将在User Comments:
之后包含文本User Comments:
这与MULTILINE标志无关; 你所看到的是find()
和matches()
方法之间的区别。 如果可以在目标string中的任何位置find匹配,则find()
将成功;而matches()
需要正则expression式匹配整个string 。
Pattern p = Pattern.compile("xyz"); Matcher m = p.matcher("123xyzabc"); System.out.println(m.find()); // true System.out.println(m.matches()); // false Matcher m = p.matcher("xyz"); System.out.println(m.matches()); // true
此外, MULTILINE
并不意味着你的想法。 如果你的目标string包含换行符,也就是说,如果它包含多个逻辑行,许多人似乎跳到了必须使用该标志的结论。 我在这里看到了几个关于这个问题的答案,但事实上,这个标记所做的只是改变锚点的行为, ^
和$
。
通常^
匹配目标string的一开始, $
和最后一个匹配(或者在最后一个换行符之前,但是我们现在就把它搁置一边)。 但是如果string包含换行符,可以通过设置MULTILINE标志来select^
和$
来匹配任何逻辑行的开始和结束,而不仅仅是整个string的开始和结束。
所以忘了MULTILINE
意思 ,只记得它的作用 :改变^
和$
锚的行为。 DOTALL
模式最初被称为“单行”(并且仍然在一些口味上,包括Perl和.NET),并且总是引起类似的混淆。 幸运的是,Java开发者在这种情况下使用了更多的描述性名称,但是对于“多行”模式没有合理的select。
在所有这些疯狂开始的Perl中,他们已经承认了他们的错误,并且在Perl 6正则expression式中摆脱了“多行”和“单行”模式。 再过二十年,也许世界其他地方也会效仿。
str.matches(regex)
行为类似于 Pattern.matches(regex, str)
,它试图将整个input序列与模式匹配并返回
当且仅当整个input序列匹配此匹配器的模式时才为
true
而matcher.find()
试图find匹配模式并返回的input序列的下一个子序列
当且仅当input序列的子序列与此匹配器的模式匹配时才返回
true
因此问题在于正则expression式。 尝试以下。
String test = "User Comments: This is \ta\ta \ntest\n\n message \n"; String pattern1 = "User Comments: [\\s\\S]*^test$[\\s\\S]*"; Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE); System.out.println(p.matcher(test).find()); //true String pattern2 = "(?m)User Comments: [\\s\\S]*^test$[\\s\\S]*"; System.out.println(test.matches(pattern2)); //true
因此,简而言之,第一个正则expression式中的(\\W)*(\\S)*
部分匹配一个空string,因为*
意味着零次或多次出现,而真正匹配的string是User Comments:
而不是整个string, d期望。 第二个失败,因为它试图匹配整个string,但它不能作为\\W
匹配一个非单词字符,即[^a-zA-Z0-9_]
和第一个字符是T
,一个单词字符。