Java Matcher.find $在单行模式下匹配换行符

时间:2019-01-28 19:19:16

标签: java regex

我正在尝试以下模式:

Pattern p = Pattern.compile("^(\\d+)$");

奇怪的是,恕我直言:

p.matcher("123\n").find() == true;
p.matcher("123\n").lookingAt() == true;  // also weird
p.matcher("123\n\n").find() == false;    // ok
p.matcher("123\na").find() == false;     // also ok
p.matcher("123\n").matches() == false;   // ok to me

在Javadocs中引用文档“ multiline flag”:

  

启用多行模式。   在多行模式下,表达式^和$分别在行终止符或输入序列的结尾之后或之前匹配。默认情况下,这些表达式仅在整个输入序列的开头和结尾匹配。

对我来说,'\ n'(即换行符)不是输入序列的结尾,因此'$'仅应在多行模式下与之匹配。

我是否缺少某些东西,或者这是Java中的错误?另外,如果您尝试相同的模式并在Javascript中测试字符串,则会看到Javascript的行为正确:

/^(\d+)$/.test("123\n") == false
/^(\d+)$/.exec("123\n") == null

(顺便说一下,我正在RHEL 7.2上使用Java 8)

谢谢!

2 个答案:

答案 0 :(得分:0)

EOL取决于操作系统。

尝试将测试模式更改为“ 123” + System.lineSeparator()

答案 1 :(得分:-1)

在多行模式下,表达式^$与以下之一匹配:

  1. 仅在行终止符之后或输入序列的结尾
  2. 仅在行终止符之前或输入序列的末尾

默认情况下,这些表达式仅在整个输入序列的开头和结尾匹配。

我可以在这里看到两个单独的问题:

    如果在目标字符串中的任何位置找到匹配项,则
  1. Matcher#find成功。 Matcher#lookingAtMatcher#matches类似,因为它总是始于该区域的开头;但与此不同的是,它不需要整个区域都匹配。这意味着以下两个都将显示true

    System.out.println(p.matcher("123\n").find());
    System.out.println(p.matcher("123\n").lookingAt()); 
    
  2. 您尚未在代码中应用多行切换。为了应用此开关,您需要将Pattern.MULTILINE作为第二个参数传递给Pattern#compile。应用此开关后,以下两项也将按照上述说明显示true

    System.out.println(p.matcher("123\n\n").find());
    System.out.println(p.matcher("123\na").find());
    

    由于缺少多行模式,因此这些表达式仅在整个输入序列的开头和结尾匹配,如果未应用多行模式,它们将返回false

演示:

import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("^(\\d+)$", Pattern.MULTILINE);
        System.out.println(p.matcher("123\n").find());
        System.out.println(p.matcher("123\n").lookingAt());
        System.out.println(p.matcher("123\n\n").find());
        System.out.println(p.matcher("123\na").find());
        System.out.println(p.matcher("123\n").matches());
    }
}

输出:

true
true
true
true
false