如何在Java中使用正则表达式捕获多行模式?

11

我有一个文本文件,需要使用正则表达式进行解析。我需要捕获的文本是多行分组的,就像这样:

truck
zDoug
Doug's house
(123) 456-7890
Edoug@doug.com
30
61234.56
8/10/2003

vehicle
eRob
Rob's house
(987) 654-3210
Frob@rob.com

对于这个例子,我需要捕获“truck”以及接下来的七行。换句话说,在这个“块”中,我有8组。这是我的尝试,但它无法捕获下一行:

(truck)\n(\w).

注意:在将正则表达式移植到Java之前,我使用程序RegExr进行测试。


2
如果您需要逐行读取输入,这与正则表达式有什么关系? - Nikita Rybak
@nikita 因为我想要形成包含换行符的组。 - lampShade
3个回答

8
(?m)^truck(?:(?:\r\n|[\r\n]).+$)*

这假设整个文本已经被读入单个字符串中(即,您不是逐行读取文件),但它并不假定行分隔符总是\n,就像您的代码一样。最少应该允许\r\n\r,这就是(?:\r\n|[\r\n])所做的。但它仍然只匹配一个分隔符,因此匹配会在块末尾的双行分隔符之前停止。
一旦匹配了一块数据,您就可以根据行分隔符将其拆分为单独的行。以下是一个示例:
Pattern p0 = Pattern.compile("(?m)^truck(?:(?:\r\n|[\r\n]).+$)*");
Matcher m = p0.matcher(data);
while (m.find())
{
  String fullMatch = m.group();
  int n = 0;
  for (String s : fullMatch.split("\r\n|[\r\n]"))
  {
    System.out.printf("line %d: %s%n", n++, s);
  }
}

输出:

第0行:卡车
第1行:zDoug
第2行:道格的房子
第3行:(123)456-7890
第4行:Edoug@doug.com
第5行:30
第6行:61234.56
第7行:2003年8月10日

我还假设每行数据至少包含一个字符,并且数据块之间的空白行确实是空白的--即没有空格、制表符或其他不可见字符。

(顺便说一句:要在RegExr中测试该正则表达式,请删除(?m)并选中multiline框。 RegExr由ActionScript驱动,因此规则略有不同。 要使用Java驱动的正则表达式测试器,请查看RegexPlanet。)


6
这个模式应该有效: ((.*|\n)*)

4

我认为为了跨越多行,您的模式应该在DOTALL模式下编译,就像这样:

Pattern p = Pattern.compile("truck\\n(.*\\n){7}", Pattern.DOTALL);

这个正则表达式如果不使用DOTALL标志会更接近正确。因为现在的.*会一开始就匹配整个文档的剩余部分。虽然它可能会回溯一点,但仍然会匹配到最后一个换行符之前的所有内容。 - Alan Moore
啊,贪心! :-) 在最后漏了一个“?”号... 非常感谢您指出来! - mazaneicha
不需要使量词变得非贪婪。只需去掉“DOTALL”标志,点号就不再匹配换行符。 - Alan Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接