【问题标题】:Java Regex: Match text between two strings with boundary conditionsJava Regex:匹配两个字符串之间的文本与边界条件
【发布时间】:2013-04-28 00:23:50
【问题描述】:

我想匹配两个字符串之间的文本,但是起始字符串有严格的边界条件。

示例输入:

start
From: h
From:b
 xyz
Subject: 
end

我需要在From:Subject: 之间进行匹配。

如果我将 (From:.*).*(Subject:) 与 dotall 一起使用,它会产生

From: h
From:b
 xyz
Subject:

但我只需要

From:b
 xyz
Subject:

因为起始字符串有严格的边界条件。这是必要的,因为起始字符串可以在文档中的任何位置,然后上面的正则表达式将匹配一个大文本而不是几行。

%%%%%%%%%%%% 问题重新定义 %%%%%%%%%%%%%% 我有需要匹配的文本:

From:<any text>
To:<any text>
Subject:<any text>

要注意的是:所有三个组件都可以在一行中,可以由一个换行符分隔,或者可以由 2 个换行符分隔...在所需匹配之前和之后有文本,其中可能包含 From:&lt;any text&gt; ,这就是为什么我需要严格的界限。

【问题讨论】:

  • 你不断地重新定义你的问题和你想要匹配的文本。这将贬低您最初创建此问题时发布的旧答案。请坚持您的原始问题,或在创建问题时尽可能清楚地说明问题。
  • 对于给您带来的不便,我深表歉意,但我认为我没有更改问题或所需的模式。在我最初的问题中,我有两次From:,因为它是实际的文本。在编辑中,我已经提到了我到底需要什么,并声明在所需的模式之前和之后都可以存在任何东西。跨度>
  • 另外,我添加了评论%%%% problem redefined %%%%,因为当两个人发布解决方案并且两者都不正确时,我认为我不够清楚来描述这个问题。这就是为什么我重新定义了这个问题,希望能更好地理解这个问题。我并不是要混淆任何人。如果我这样做了,我很抱歉。

标签: java regex parsing match


【解决方案1】:

试试这个:

String input = "start From: h From:b xyz Subject: end";
Matcher matcher = Pattern.compile("(?<=^((?!From:).)*(From: [A-Za-z0-9] ))(.+?)(Subject:)").matcher(input);
if (matcher.find())
{
    System.out.println(matcher.group());
}

输出:From:b xyz Subject:


正则表达式的解释((?&lt;=^((?!From:).)*(From: [A-Za-z0-9] ))(.+?)(Subject:)):

  • (?&lt;=开始往后看
  • ^字符串的开头
  • ((?!From:).) 如果向前看并且看不到“From:”,则匹配任何字符
  • * 匹配上一条语句零次或多次
  • (From: [A-Za-z0-9] )) 匹配第一个“发件人:”及其内容
  • )别往后看
  • (.+?) 匹配我们要查找的字符串
  • (Subject:) 匹配主题字段

【讨论】:

  • 你是如何测试这个的? Java 不支持无限后视(但某些版本有一个错误,导致他们忘记了这一点并尝试了)。此外,OP 的数据是多行的形式,而不是像你所拥有的那样都在一行上。 (OP 可能在您编写答案时编辑了问题。如果您这样做的速度足够快,SO 不会将该问题标记为已编辑。)
  • 它没有给出正确的结果。我尝试输入"start From: h strt From:b xyz Subject: end",它匹配strt From:b xyz Subject:,这是不正确的。我需要从From:开始的所有东西
  • @AlanMoore 不是吗?我在 Eclipse 中使用 Java 7 对其进行了测试,它运行良好......
  • 哦。我不知道为什么。我在 Java 7 中使用 Netbeans,它给了我不同的答案.. 输入:"start From: h strt From:b xyz Subject: end".. 输出:strt From:b xyz Subject: 与正则表达式 (?&lt;=^((?!From:).)*(From: [A-Za-z0-9] ))(.+?)(Subject:)
  • @user2200660 您在此评论中的输入与最初在您的问题中提供的不同。因此,您的输出预计会有所不同。
【解决方案2】:

建议您一次匹配一行,而不是在 DOTALL 模式下使用 .* 断言该行不以 From: 开头。

"(?m)^From:.*[\r\n]+(?:(?!From:).*[\r\n]+)*Subject:.*$"

这是最低限度的实现。根据您的文本的结构,它仍然可能匹配太多或太慢(尤其是在无法匹配的情况下)。这是一个更强大的版本:

"(?m)^(?>From:.*[\r\n]+)(?>(?!From:|Subject:).*[\r\n]+)*+Subject:.*$"

【讨论】:

  • 它不适用于显示的示例...我将在帖子中再次解释该问题。
【解决方案3】:

简单地说:

From\:\w*(?!From\:\w*)\n*\w*\n*Subject:\w*

演示:https://regex101.com/r/mX9kC7/3

【讨论】:

    【解决方案4】:

    使用多行修饰符和负前瞻:

    (?s)From:((?!From:).)*?Subject:@ regex101

    注意:regex101 fiddle 包含实时正则表达式和测试数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 2017-04-02
      • 2022-08-04
      • 2019-11-27
      相关资源
      最近更新 更多