正则表达式以重复模式捕获每个组的第一次出现

Regex capturing the first occurrence of every group in a recurring pattern

假设我有以下文本:

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

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

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

它有三个捕获组,可以捕获名称、地址和城市的值(如果它们出现在文本中)。这里还有几个例子:https://regex101.com/r/37nemH/6EDIT 预先排序不固定,也可能字段 不是 \t 个字符分隔。

现在一切正常,我遇到的唯一小问题是同一个文本中的一个字段出现两次,正如我放在 regex101 上的最后一个示例所示:

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

我想要的是第二个捕获组匹配第一个地址,即Street 123 ABC,最好让第二次出现在"City"组,即

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

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

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

如果词序可以任意,部分或全部项目可以缺失,使用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: 或字符串结尾。

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

^.*?(?:(?: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`