正则表达式以循环模式捕获每个组的首次出现

时间:2018-11-22 10:46:38

标签: regex capturing-group negative-lookbehind

假设我有以下文字:

Fragment

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

Objects

具有三个捕获组,它们可以捕获名称,地址和城市的值(如果它们出现在文本中)。这里有更多示例:https://regex101.com/r/37nemH/6编辑顺序不是预先固定的,也可能发生字段Name: John Doe\tAddress: Street 123 ABC\tCity: MyCity 字符分隔的情况。

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

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

我想要的是让第二个捕获组匹配 first 地址,即\t,最好让第二个匹配项在“ City”组中匹配,即

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

从概念上讲,我尝试使用反面的方式进行此操作,例如将Street 123 ABC替换为1: John Doe 2: Street 123 ABC 3: MyCity\tAddress: Other Address ,即确保另一个(?:Address: (.+?))标签未在文本中进行(?:(?<!.*Address: )Address: (.+?))匹配。但是,负向后看不允许任意长度,因此这显然行不通。

可以使用正则表达式来实现吗?

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

如果单词顺序可以是任意的并且某些或所有项目可能会丢失,则使用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:或字符串结尾。