java - 负前瞻正则表达式在 Java 中不起作用

标签 java regex pattern-matching regex-lookarounds

以下正则表达式在测试 here 时成功运行,但是当我尝试将它实现到我的 Java 代码中时,它不会返回匹配项。它使用否定前瞻来确保 MAIN LEVELBedrooms 之间不会出现换行符。为什么它不能在 Java 中运行?

正则表达式

^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)

Java

pattern = Pattern.compile("^\\s*\\bMAIN LEVEL\\b\\n(?:(?!\\n\\n)[\\s\\S])*\\bBedrooms:\\s*(.*)");
    match = pattern.matcher(content);      
    if(match.find())
    {
        //Doesn't reach here
        String bed = match.group(1);
        bed = bed.trim();
    }

content 只是从文本文件中读取的字符串,其中包含上面链接的演示中显示的确切文本。

File file = new File("C:\\Users\\ME\\Desktop\\content.txt"); 
 content = new Scanner(file).useDelimiter("\\Z").next();

更新:

我更改了我的代码以包含多行修饰符 (?m),但它打印出“null”。

pattern = Pattern.compile("(?m)^\\s*\\bMAIN LEVEL\\b\\n(?:(?!\\n\\n)[\\s\\S])*\\bBedrooms:\\s*(.*)");
    match = pattern.matcher(content);
    if(match.find())
    {   // Still not reaching here
        mainBeds=match.group(1);
        mainBeds= mainBeds.trim();
    }
  System.out.println(mainBeds);     // Prints null

最佳答案

问题:

Alan Moore's answer 中所述,这是文件中使用的 Line-Separators 格式 (\r\n) 与您的模式指定的格式 (\n):

原代码:
Pattern.compile("^\\s*\\bMAIN LEVEL\\b\\n(?:(?!\\n\\n)[\\s\\S] )*\\b卧室:\\s*(.*)");

注意:我解释一下\r\n分别代表什么,以及\r\n的上下文和区别>\n,在 “旁注” 部分的第二项中。


解决方案:

  1. 大多数/所有 Java 版本:
    您可以使用 \r?\n 来匹配这两种格式,这在大多数情况下就足够了

  2. 大多数/所有 Java 版本:
    您可以使用 \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029] 来匹配“任何 Unicode 换行序列”

  3. Java 8 及更高版本:
    您可以使用 Linebreak Matcher (\R) .它等同于第二种方法(上文),只要有可能(Java 8 或更高版本),这是推荐的方法

结果代码(第三种方法):
Pattern.compile("^\\s*\\bMAIN LEVEL\\b\\R(?:(?!\\R\\R)[\\s\\S] )*\\b卧室:\\s*(.*)");


旁注:

  1. 可以将\\R\\R替换为\\R{2},这样可读性更好。

  2. 存在不同格式的换行符并在不同的系统中使用,因为早期的操作系统从机械打字机(如打字机)继承了“换行符逻辑”。

    代码中的 \r 代表一个Carriage-Return,又名 CR 。这背后的想法是将键入光标返回到行的开头。

    代码中的 \n 代表一个Line-Feed,又名 LF 。这背后的想法是将打字光标移动到下一行。

    最常见的换行符格式是 CR-LF (\r\n),主要由 Windows 使用;和 LF (\n),被大多数类 UNIX 系统使用。这就是为什么\r?\n 在大多数情况下足够 的原因,并且您可以可靠地将它用于旨在用于家庭级用户。

    但是,一些(罕见的)操作系统,通常在服务器等工业级设备中,可能会使用CRLF -CR,或者完全是其他东西,这就是为什么第二种方法中有这么多字符,所以如果您需要代码与every<兼容/strong> 系统,您将需要第二种方法,最好是第三种方法。

  3. 这里有一个有用的方法来测试你的模式在哪里失败:

    String content = "..."; //Replace "..." with your content.
    String patternString = "..."; //Replace "..." with your pattern.
    String lastPatternSuccess = "None. You suck at Regex!";
    for (int i = 0; i <= patternString.length(); i++) {
      try {
        String patternSubstring = patternString.substring(0, i);
        Pattern pattern = Pattern.compile(patternSubstring);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
          lastPatternSuccess = i + " - Pattern: " + patternSubstring + " - Match: \n" + matcher.group();
        }
      } catch (Exception ex) {
        //Ignore and jump to next
      }
    }
    System.out.println(lastPatternSuccess);
    

关于java - 负前瞻正则表达式在 Java 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34477623/

相关文章:

regex - 用于测试合规 FATCA 全局中介识别码 (GIIN) 的正则表达式是什么?

java - 无法在 j2me 上显示传感器信息

java - 无法使用 jersey-quickstart-webapp 原型(prototype)创建新的 Maven 项目

regex - htaccess - 如何比较环境变量 - 检查 2 个环境变量是否相同

haskell - 这个模式匹配发生了什么?

php - 正则表达式 PHP,将所有链接与特定文本匹配

regex - Redis 或 checkin MATCH

java - 哪个 Java PDF 库允许我以不同方向打印页面的不同部分?

java - Swing - Qt 信号/槽的替代品

regex - perl 正则表达式替换非单词字符,除了::