使用正则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 ,一个单词字符。