正则表达式匹配特定文件格式和空字符串

5

我将使用正则表达式来匹配以下格式的文件:

FILTER
<data>
ORDER
<data>

现在,我需要提取的是<data>部分,这本来很简单,但我有以下困难:

1)这个模式可以重复(之间没有换行符)

2)可能没有<data>

特别地,此文件是可以的:

FILTER
test1
ORDER
test2
FILTER
test3
ORDER
FILTER
ORDER

我需要以下几组数据:"test1", "test2", "test3", "", "", ""
我已经尝试使用的正则表达式是:(?:FILTER\n(.*)\nORDER\n(.*))*
这里可以测试此正则表达式。
我对正则表达式并不熟悉,感谢您的帮助。

我会简化它为:FILTER(.*?)ORDER(.*?)(?=FILTER|$),然后相应地去除换行符。请注意,您需要包括s修饰符以匹配点.的换行符。 - HamZa
@HamZa 这并不完全有效... 另外我也不是很理解 https://regex101.com/r/bT2rD7/3 - sadfsa sdfasdf
你给我的正则表达式添加了 m 修改符号,这将改变整个含义。请删除它。(我让我的正则表达式可点击了吗?) - HamZa
@HamZa 噢,现在看起来不错。谢谢 :D - sadfsa sdfasdf
请注意,我的展开正则表达式可能比 FILTER(.*?)ORDER(.*?)(?=FILTER|$) 更有效率。 - Wiktor Stribiżew
我添加了另一个解决方案并修改了之前的方案。然而,我的解决方案看起来是最有效的。 - Wiktor Stribiżew
2个回答

2
您可以使用基于懒惰点匹配和温顺贪婪标记的正则表达式:
(?s)FILTER(.*?)ORDER((?:(?!FILTER).)*)
           ^-^       ^--------------^

使用DOTALL修饰符与此正则表达式。这里是一个正则表达式演示.*?匹配任何字符,但尽可能少地匹配,因此只匹配到第一个ORDER(?:(?!FILTER).)*贪婪模式匹配任何非FILTER的文本。它是多字符序列的否定字符类的一种同义词。
您可以按以下方式展开它:
FILTER([^O]*(?:O(?!RDER)[^O]*)*)ORDER([^F]*(?:F(?!ILTER)[^F]*)*)

查看 正则表达式演示(此正则表达式不需要 DOTALL 模式)。
String s = "FILTER\ntest1\nORDER\ntest2\nFILTER\ntest3\nORDER\nFILTER\nORDER";
Pattern pattern = Pattern.compile("(?s)FILTER(.*?)ORDER((?:(?!FILTER).)*)");
Matcher matcher = pattern.matcher(s);
List<String> results = new ArrayList<>();
while (matcher.find()){
    if (matcher.group(1) != null) {
        results.add(matcher.group(1).trim());
    } 
    if (matcher.group(2) != null) {
        results.add(matcher.group(2).trim());
    } 
} 
System.out.println(results);  // => [test1, test2, test3, , , ]

看一下 IDEONE演示 如果您需要确保FILTERORDER分隔符字符串出现为单独的行,只需在它们周围使用^$并添加MULTILINE修饰符(以便^能匹配一行的开头和$能匹配一行的结尾):
(?sm)^FILTER$(.*?)^ORDER$((?:(?!^FILTER$).)*)
 ^^^^

另一个正则表达式

这看起来很不错,但是你所说的“unrolling”是什么意思? - sadfsa sdfasdf
@Andreas:这个模式可以重复(中间没有换行符。里面只有一个ORDER,因此第二个温和的贪婪标记不应该跳过起始定界符,在这里是FILTER。使用温和的贪婪标记,我们可以添加单词边界和其他限制。只需要更多来自OP的反馈。 - Wiktor Stribiżew
通过您的更新答案,最后一个正则表达式已经接近完成了,但是捕获的<data>是错误的,因为您也捕获了换行符。 - Andreas
@WiktorStribiżew 一条建议:保持简单愚蠢原则(KISS)。这个“展开”的正则表达式非常庞大且对大多数开发者来说很难理解。微观优化需要有一个真正的好理由。另请参见http://programmers.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil - HamZa
HamZa,这不是过早的。我每天处理数百GB的数据,更喜欢保险起见 - 始终如此。OP从未展示过真实的例子,因此展开版本(特别是在Java中,堆栈溢出问题并不少见)可能是唯一正确的方向。Andreas,trim()在代码中用于从捕获的值的开头和结尾删除冗余的空格,请参见代码演示。 - Wiktor Stribiżew
显示剩余3条评论

0
我会使用以下正则表达式:

FILTER(?:\n(?!ORDER)(.*))?\nORDER(?:\n(?!FILTER)(.*))?

你可以在regex101上进行测试。


我刚刚更新了它,去掉了需要一个尾随换行符的要求,现在好一些了吗? - Aaron
Wiktor的答案更符合需求,你的没有返回空字符串。 - sadfsa sdfasdf
哎?它确实会返回空字符串,在你的例子中,第二个匹配中的第二组为空,最后一个匹配中的第一组和第二组都为空。 - Aaron

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