我试图使用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?
Run Code Online (Sandbox Code Playgroud)
Tim*_*ker 284
首先,您在不正确的假设下使用修饰符.
Pattern.MULTILINE或(?m)告诉Java接受锚点^并$在每行的开头和结尾匹配(否则它们只匹配整个字符串的开头/结尾).
Pattern.DOTALL或(?s)告诉Java允许点匹配换行符.
其次,在你的情况下,正则表达式失败是因为你正在使用matches()期望正则表达式匹配整个字符串的方法 - 这当然不起作用,因为(\\W)*(\\S)*匹配后还剩下一些字符.
因此,如果您只是寻找一个以字符串开头的字符串User Comments:,请使用正则表达式
^\s*User Comments:\s*(.*)
Run Code Online (Sandbox Code Playgroud)
有Pattern.DOTALL选项:
Pattern regex = Pattern.compile("^\\s*User Comments:\\s+(.*)", Pattern.DOTALL);
Matcher regexMatcher = regex.matcher(subjectString);
if (regexMatcher.find()) {
ResultString = regexMatcher.group(1);
}
Run Code Online (Sandbox Code Playgroud)
ResultString 然后将包含文本 User Comments:
Ala*_*ore 41
这与MULTILINE标志无关; 你所看到的是find()和matches()方法之间的区别. find()如果匹配可以在目标字符串中的任何位置找到,则成功,同时matches()期望正则表达式匹配整个字符串.
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
Run Code Online (Sandbox Code Playgroud)
此外,MULTILINE并不意味着你的想法.如果你的目标字符串包含换行符 - 也就是说,如果它包含多个逻辑行,那么许多人似乎都会得出结论,你必须使用该标志.我已经在这里看到了几个关于这个效果的答案,但事实上,所有那个标志所做的就是改变锚点的行为,^并且$.
通常^匹配目标字符串的最开头,并$匹配最后一端(或者在结尾处的换行符之前,但我们暂时将它留在一边).但是如果字符串包含换行符,则可以通过设置MULTILINE标志来选择^和$匹配任何逻辑行的开头和结尾,而不仅仅是整个字符串的开头和结尾.
所以忘记什么MULTILINE 意思,只记住它的作用:改变^和$锚的行为. DOTALLmode最初被称为"单行"(并且仍然有一些版本,包括Perl和.NET),它总是引起类似的混淆.我们很幸运,Java开发人员在这种情况下采用了更具描述性的名称,但"多线"模式没有合理的替代方案.
在所有这些疯狂开始的Perl中,他们承认了他们的错误并且在Perl 6 regex中摆脱了"多线"和"单线"模式.再过二十年,也许世界其他地方也会效仿.
Ama*_*osh 21
str.matches(regex) 表现就像 Pattern.matches(regex, str)尝试将整个输入序列与模式匹配并返回
trueif,且仅当整个输入序列与此匹配器的模式匹配时
而matcher.find() 尝试找到与模式匹配的输入序列的下一个子序列并返回
true当且仅当,一个子输入序列的此匹配的模式匹配
因此问题在于正则表达式.请尝试以下方法.
String test = "User Comments: This is \t a\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
Run Code Online (Sandbox Code Playgroud)
因此,简而言之,(\\W)*(\\S)*第一个正则表达式中的部分与空字符串匹配,*表示零次或多次出现,而实际匹配的字符串是,User Comments:而不是您期望的整个字符串.第二个失败,因为它试图匹配整个字符串但它不能\\W匹配非单词字符,即[^a-zA-Z0-9_]第一个字符是T单词字符.