代码之家  ›  专栏  ›  技术社区  ›  Dean Schulze

用于查找特定长度的多行的Java正则表达式

  •  5
  • Dean Schulze  · 技术社区  · 14 年前

    我试图使用Java正则表达式来匹配跨多行的模式。模式有一行以“A”开头,后跟50个字符,然后有一行或多行以“B”开头,后跟50个字符:

    A...    //  exactly 50 chars after the A
    B...
    B...
    

    但是Java正则表达式似乎不支持这一点。

    这里有一个regexp,适用于一个a和一个B行:

    A.{50}[\\n[\\n\\r]]B.{50}[\\n[\\n\\r]]
    

    下面是为查找一个或多个B行而修改的同一regexp:

    A.{50}[\\n[\\n\\r]][B.{50}[\\n[\\n\\r]]]+
    

    但是,这个regexp只在第一行B上找到前导B字符。

    我用 [\\n[\\r\\n]] 同时处理DOS和UNIX新行。启用多行模式不会影响结果。

    问题似乎是当我使用带“+”的方括号将B行的regexp转换为可以捕获多行的字符类时。

    Java正则表达式中是否有不允许“.”字符或花括号指定确切的行长度的内容?

    6 回复  |  直到 14 年前
        1
  •  0
  •   True Soft    14 年前

    在以下正则表达式中:

    (A[^\r\n]{50}(\r\n|\n))(B[^\r\n]{50}(\r\n|\n))+
    

    我用过 [^\r\n] 匹配任何不匹配的字符 \r \n . 你可以换成 [\d] 例如,如果你有数字。

    http://www.myregextester.com/?r=b7c3ca56

    在本例中,regex匹配除最后一行之外的所有内容。

        2
  •  0
  •   andcoz    14 年前

    这应该有效:

    String input = "A1234567890\nA12345678\nA12345678\nB12345678\nA123456\nA1234567\nZA12345678\nB12345678\nA12345678\nB12345678\nB12345678\nB12345678\nB1234567\nA12345678\nB12345678";
    
    String regex = "^A.{8}$((\\r|\\r\\n|\\n)^B.{8}$)+(\\r|\\r\\n|\\n|\\z)";
    
    Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
    Matcher matcher = pattern.matcher(input);
    
    while (matcher.find()) {
    System.out.println("matches from " + matcher.start() + " to " + matcher.end());
    }
    

    注:

    1. 使用 ^ , $ MULTILINE 避免与以“ZA”开头的行匹配。
    2. 使用 (\\r|\\r\\n|\\n) 以匹配unix、windows和旧的mac os系列。
    3. 使用 (\\r|\\r\\n|\\n|\\z) 匹配最后一条没有行尾的B行

    手术室,我用过 8 而不是 50 增加可读性。

        3
  •  0
  •   codaddict    14 年前

    要同时处理Unix和Dos样式的换行符,可以使用:

    \\r?\\n
    

    你也可以把一个或多个 B 行不正确,您正在使用 [] 对于分组,您应该使用 (?: ) 相反。

    试试这个正则表达式:

    A.{50}\\r?\\n(?:B.{50}(?:\\r?\\n)?)+
    

    Regex tested here

        4
  •  0
  •   Alan Moore Chris Ballance    14 年前

    圆点和花括号工作得很好;是你的正则表达式的其余部分出错了。看看这个:

    Pattern p = Pattern.compile("^A.{50}(?:(?:\r\n|[\r\n])B.{50})+$");
    

    (?:\r\n|[\r\n]) 匹配CRLF序列、仅CR或仅LF。(我本来可以像你一样用两个反斜杠,但这也行)。

    如果使用regex从一些较大的文本中提取匹配项,则需要以多行模式编译它,以便 ^ $ 定位点可以在线边界处匹配。如果要匹配整个字符串,请将其保留为默认模式,以便它们只在字符串的开头和结尾匹配。

        5
  •  0
  •   Community Anvaka    7 年前

    匹配换行符序列的正确方法是:

    "(?:(?>\\u000D\\u000A)|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029)"
    

    当然,这是用Javas slackbashy字符串表示法,就像您可能传递给 Pattern.compile . 更合理的语言让您只需以下几点:

    (?:(?>\x0D\x0A)|\v)
    

    但是,Javas正则表达式从来就不是那么合理,甚至这实际上是对 how bad they really are . 爪哇 poor support for whitespace detection 只是它无数麻烦的地方之一。

    祝你好运:你会需要它的。

        6
  •  0
  •   Tim Pietzcker    14 年前

    这也应该有效:

    Pattern regex = Pattern.compile("^A.{50}$\\s+(?:^B.{50}$\\s*)+(?:^|\\z)", Pattern.MULTILINE);
    

    背后的原因是 ^ 在队伍的开始, $ 匹配行尾的(可选)换行符之前,以及 \s 匹配包含 \r \n . 因为我们用它 $ ^ ,它只能匹配换行符,不能匹配其他空格。

    这个 (?:^|\\z) 用于确保我们不会意外地匹配 B 行。如果行从不以空白开头,可以去掉这一点。