【问题标题】:Match for multiple lines of text between delimiters in Java匹配Java中分隔符之间的多行文本
【发布时间】:2014-09-03 23:13:57
【问题描述】:

如何在 Java 中匹配分隔符之间的多行文本?

问题最好用一个例子来解释:

...
unimportant text
EndOfEntry
Key=Value
unimportant text
maybe a few lines of unimportant text
AnotherKey=AnotherValue
EndOfEntry
more unimportant text
...

在上面,我想匹配 Key=Value.*AnotherKey=AnotherValue 一起出现在一个条目中。我只是想知道模式是否出现——我不需要替换任何东西。

但是,如果给定多个条目,则具有相同的期望匹配,例如:

...
unimportant text
EndOfEntry
Key=Value
unimportant text
maybe a few lines of unimportant text
AnotherKey=NotMyValue
EndOfEntry
RandomKey=Value
unimportant text
maybe a few lines of unimportant text
AnotherKey=AnotherValue
EndOfEntry
more unimportant text
...

我不希望成功匹配上述内容,因为我们在单个“条目”中看不到确切的 Key=Value 和 AnotherKey=AnotherValue。相反,我们在第一个条目中看到 Key=Value,在第二个条目中看到 AnotherKey=AnotherValue。

我一直在尝试使用类似的正则表达式(当然 \S\s 可以用 Pattern 的 DOTALL 选项替换):

Key=Value[\S\s]*?AnotherKey=AnotherValue

但当然两者都匹配。我也试过:

Key=Value[^EndOfEntry]*?AnotherKey=AnotherValue

但这不起作用,因为没有点而且我们根本不匹配换行符。

是否有一个正则表达式可以精确匹配我正在寻找的内容?是否会简化首先去除换行符或其他一些两步处理的事情(我只是为了教育而试图避免)?

【问题讨论】:

  • 我不清楚您的需求。你能提供一个更好的输入示例和你想要的输出吗?
  • Key=Value[\S\s]*?AnotherKey=AnotherValue[\S\s]*?EndOfEntry 做你想要的?是否保证每个条目都以 Key=Value 开头?
  • 没关系,你需要一个否定的环视,因为这在你的例子中会匹配太多。正则表达式在这里可能不是正确的工具。
  • @Fede,所需的输出应该只是匹配或不匹配
  • 我同意@adamdc78;尝试使用一个正则表达式完成所有工作并不是正确的方法。我会遍历每一行并测试匹配。当你点击EndOfEntry时,使用计数器或其他东西来跟踪。

标签: java regex multiline


【解决方案1】:

你应该简单地使用:

\bKey=Value\b(?:(?!EndOfEntry).)*?\bAnotherKey=AnotherValue\b

(使用 DOTALL 标志,正如您在问题中所建议的那样)。

现场体验here on regex101


工作原理:

我基本上只是用那个表达式替换了你的.*((?!EndOfEntry).)*,它大致代表任何不包含EndOfEntry的东西

此外,为了避免与 RandomKey=ValueAnotherKey=AnotherValue 匹配,因为 RandomKey=Value 也会匹配 Key=Value(例如),我添加了另一个小调整:

我已经用\b(断言我们处于单词边界)(或\s,对于任何空格字符)包围了你的配对,所以我们只有在整个单词匹配时才会匹配.


这是一段 Java 代码,它使用我针对您的示例建议的正则表达式:

final Pattern pattern = Pattern.compile("\\bKey=Value\\b(?:(?!EndOfEntry).)*?\\bAnotherKey=AnotherValue\\b", Pattern.DOTALL);

final String invalid = "unimportant text\n" +
                "EndOfEntry\n" +
                "Key=Value\n" +
                "unimportant text\n" +
                "maybe a few lines of unimportant text\n" +
                "AnotherKey=NotMyValue\n" +
                "EndOfEntry\n" +
                "RandomKey=Value\n" +
                "unimportant text\n" +
                "maybe a few lines of unimportant text\n" +
                "AnotherKey=AnotherValue\n" +
                "EndOfEntry\n" +
                "more unimportant text";

final String valid = "unimportant text\n" +
                "EndOfEntry\n" +
                "Key=Value\n" +
                "unimportant text\n" +
                "maybe a few lines of unimportant text\n" +
                "AnotherKey=AnotherValue\n" +
                "EndOfEntry\n" +
                "more unimportant text";

System.out.println(pattern.matcher(invalid).find());
System.out.println(pattern.matcher(valid).find());

输出:

false
true

【讨论】:

  • 我不相信这会在 Java 中工作。甚至 regex101 的第一个捕获组错误。
  • 我认为它确实有效,我看不出 regex101 上的示例有什么问题。不过,也许我没有正确理解这个问题。我会让 OP 看看我的答案,以防万一我可能是对的:)
  • 啊,您使导致问题的组未被捕获。当我在 regexplanet(一个实际的 Java 正则表达式测试器)上运行它时,它与提供的输入不匹配。不过,如果您有可用的 Java 代码,我会接管 RegexPlanet。我站得更正了。编辑:如果我将有效字符串作为标准包括在内,那将会有所帮助。我的错!
  • 也不适用于我在 regexplanet.com 上:fiddle.re/d7x4y6 并单击 Java。但如果它在 Java 中工作,我会接受它,谢谢!由于捕获组不用于替换,括号可以变成方括号吗?
  • 是的,在 RegexPlanet 上不起作用,原因很简单,显然转到换行符不对应于附加 \n... 只需替换 @987654336 @ 由一些 \s\b 编写,它也在 RegexPlanet 上工作 :)
猜你喜欢
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
  • 2017-05-29
  • 2016-11-05
  • 1970-01-01
  • 2016-01-03
相关资源
最近更新 更多