【问题标题】:Regex capturing the first occurrence of every group in a recurring pattern正则表达式以重复模式捕获每个组的第一次出现
【发布时间】:2019-04-25 00:48:53
【问题描述】:

假设我有以下文本:

Name: John Doe\tAddress: Street 123 ABC\tCity: MyCity

我有一个正则表达式(有点复杂,但归结为这个):

^(?:(?:(?:Name: (.+?))|(?:Address: (.+?))|(?:City: (.+?)))\t*)+$

它具有三个捕获组,可以捕获名称、地址和城市的值(如果它们出现在文本中)。更多示例如下:https://regex101.com/r/37nemH/6EDIT 事先没有固定顺序,也可能出现字段not\t 字符分隔的情况。

现在这一切都很好,我唯一的小问题是当一个字段在同一文本中出现两次时,如我在 regex101 上放置的最后一个示例所示:

Name: John Doe\tAddress: Street 123 ABC\tCity: MyCity\tAddress: Other Address

我想要的是让第二个捕获组匹配第一个地址,即Street 123 ABC,最好让第二个匹配项在“City”组内匹配,即 p>

1: John Doe
2: Street 123 ABC
3: MyCity\tAddress: Other Address

从概念上讲,我尝试用消极的后视来做到这一点,例如将(?:Address: (.+?)) 替换为(?:(?<!.*Address: )Address: (.+?)),即确保Address: 匹配没有被另一个Address: 标记在文本中的某处进行。但是,消极的后视不允许任意长度,所以这显然是行不通的。

这可以使用正则表达式实现吗?如何实现?

【问题讨论】:

  • 尝试连续匹配和捕获值,^(.*?)Name:\s+(.*?)\s+Address:\s+(.*?)\s+(?:City:\s+(.*?)\s*)?$,参见demo
  • 如果词序可以是任意的,并且可以缺少部分或全部项目,那么使用 3 个单独的模式来提取您需要的位会容易得多。
  • 当字段没有明确分隔时,这是否也有效?例如。文字是否符合Name: John DoeAddress: Street 123 ABC?
  • 1) Name, 2) City, 3) Address
  • 这就像一个魅力。然后我会想像我在问题中提到的那样,将 City 匹配为MyCity\tAddress: Other Address 只是要求太多,不是吗;)

标签: regex capturing-group negative-lookbehind


【解决方案1】:

如果词序可以是任意的,并且可以缺少部分或全部项目,则使用 3 个单独的模式来提取所需的位会容易得多。

姓名 (demo):

^.*?Name:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

城市 (demo):

^.*?City:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

地址 (demo):

^.*?Address:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

详情

  • ^ - 字符串开头
  • .*? - 除换行符以外的任何 0+ 字符,尽可能少
  • Address: - 一个关键字停下来寻找预期的匹配
  • \s* - 0+ 个空格
  • (.*?) - 第 1 组:除换行符之外的任何 0+ 个字符,尽可能少...
  • (?=\s*(?:Name:|Address:|City:|$)) - 最多但不包括 0 个或多个空格,后跟 Name:Address:City: 或字符串结尾。

【讨论】:

    【解决方案2】:

    对于您陈述的问题,您可以将此正则表达式与条件构造一起使用:

    ^.*?(?:(?:Name: (.+?)|(Address: )(.+?)|City: ((?(2).*?Address: )*.+?))\t*)+$
    

    RegEx Demo

    您的值在捕获的组 1、3、4 中可用。

    捕获组 2 用于文字标签 "Address: "

    这里,(?(2).*?Address: )* 是一个条件构造,这意味着如果捕获的第 2 组存在,则在第 4 组中匹配文本,直到找到下一个 Address:(此匹配的 0 个或多个)。

    对于文本Name: John Doe Address: Street 123 ABC City: MyCity Address: Second address,它将具有以下匹配项:

    Group 1.    169-177 `John Doe`
    Group 2.    178-187 `Address: `
    Group 3.    187-201 `Street 123 ABC`
    Group 4.    210-240 `MyCity Address: Second address`
    

    【讨论】:

    • 我喜欢你的方法。我已经接受了另一个答案,因为这个答案有点难以概括(比如:不仅地址字段可以出现两次,而且任何字段都可以出现),但很高兴看到有一个解决方案也可以获得我的首选行为
    • 谢谢。这是您的特权,但 Wiktor 的正则表达式不会在 City 捕获组中捕获 Address: Second address
    猜你喜欢
    • 2015-07-24
    • 2017-10-07
    • 2020-12-16
    • 2017-05-13
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    相关资源
    最近更新 更多