仅当组内存在时才匹配组内的组

时间:2018-01-17 13:48:23

标签: .net regex

我希望使用正则表达式模式H-\d{4}捕获整行,以及(可选)ID,例如H-1234

这是两个样本行,一个带ID,另一个没有ID:

  

带有H-5722 id的样品行

     

没有ID的示例行

在第一个ALL中应该捕获整行,ID H-5722。在第二个ALL中应捕获整行,ID应​​为空。

这个正则表达式适用于第一行,捕获ALL和ID:

^(?<ALL>.*?(?<ID>H-\d{4})\b.*)$

但是它没有像预期的那样匹配第二行,因为它没有ID。

因此,我尝试使用?零或一修饰符(?:(?<ID>H-\d{4}))?的非捕获组使ID捕获成为可选项,或者修改ID组以便它可以捕获表达式或空字符串(?<ID>H-\d{4}|)

^(?<ALL>.*?(?:(?<ID>H-\d{4})\b)?.*)$

^(?<ALL>.*?(?<ID>H-\d{4}|)\b.*)$

通过这些修改,ALL捕获了两个示例中的整行。但它并没有捕获ID。

我怎样才能做到这一点?

我使用.NET正则表达式实现,但我认为它与其他实现非常相似。

4 个答案:

答案 0 :(得分:1)

使用替换:

^(?<ALL>(?!.*H-\d{4}\b).*|.*?(?:(?<ID>H-\d{4})\b).*)$

请参阅https://regex101.com/r/dZx3b1/1/

或者使用unrolled tempered greedy token(表现)

^(?<ALL>[^H\n]*(?:H(?!-\d{4}\b)[^H\n]*)*(?<ID>H-\d{4}\b)?.*)$

请参阅https://regex101.com/r/9ILEhw/1/

基本上强制使用ID组,如果可以找到它。

您的方法失败,因为.*?始终与初始空字符串匹配,跳过可选的ID模式,.*与实际字符串匹配。

答案 1 :(得分:1)

.NET中,您可以使用

(?:(?<ALL>.*(?<ID>\bH-\d{4}\b).*)|(?<ALL>.+))

a working demo on regex101.com

<小时/> 细分,这说:

(?:                                 # open non-capturing group
   (?<ALL>.*(?<ID>\bH-\d{4}\b).*)   # with ID
   |                                # or
   (?<ALL>.+)                       # without ID
)

无论您的内容是什么,ALL都会保留完整的行,ID只有在H-1234形式的ID确实存在时才会出现。正如评论中所述,这只能在.NETsee here on SO)中使用,并且与PCRE之类的语法无效。

答案 2 :(得分:1)

尝试更具体的更改:

^(?<ALL>[^H\n\r]*(?:(?<ID>H-\d{4}).*|.[^H\n\r]*)*)

不是最短但最快的。

Live demo

答案 3 :(得分:0)

以下模式似乎有效:

^((?:(?!H-\d{4}).)*(H-\d{4})?\b.*)$

在存在H想法的情况下,它将在第二个捕获组中可用。如果不是,则第二个捕获组将为空。在任何一种情况下,整个字符串都会出现在第一个捕获组中。

string input = "Sample line with H-123 id";
Regex r1 = new Regex(@"^((?:(?!H-\d{4}).)*(H-\d{4})?\b.*)$");
Match match = r1.Match(input);
if (match.Success)
{
    Console.WriteLine("First capture group: {0}", match.Groups[1].Value);
    Console.WriteLine("Second capture group: {0}", match.Groups[2].Value);
}

Demo