正则表达式:以不同顺序匹配组而不重复组

Jim*_*mmy 14 regex

假设我有两个这样的字符串:

XABY
XBAY
Run Code Online (Sandbox Code Playgroud)

一个匹配两者的简单正则表达式将如下所示:

X(AB|BA)Y
Run Code Online (Sandbox Code Playgroud)

但是,我有一个案例,其中A和B是复杂的字符串,我正在寻找一种方法来避免必须指定它们两次(在|的每一侧).有没有办法做到这一点(可能比指定它们两次更简单)?

谢谢

Ala*_*ore 22

X(?:A()|B()){2}\1\2Y
Run Code Online (Sandbox Code Playgroud)

基本上,您使用空捕获组在匹配时检查每个项目,然后反向引用确保已检查所有项目.

请注意,这依赖于未记录的正则表达式行为,因此无法保证它在您的正则表达式中起作用 - 如果确实如此,则无法保证它会随着该风格的发展而继续工作.但据我所知,它适用于支持反向引用的每种风格.(编辑:它在JavaScript中不起作用.)

编辑:你说你正在使用命名组捕获匹配的部分,这给正则表达式增加了很多视觉混乱,如果不是真正的复杂性.好吧,如果你碰巧使用.NET正则表达式,你仍然可以使用简单的编号组作为"复选框".这是一个简单的例子,它可以在不知道内部顺序的情况下查找和挑选一堆月日字符串:

  Regex r = new Regex(
    @"(?:
        (?<MONTH>Jan|Feb|Mar|Apr|May|Jun|Jul|Sep|Oct|Nov|Dec)()
        |
        (?<DAY>\d+)()
      ){2}
      \1\2",
    RegexOptions.IgnorePatternWhitespace);

  string input = @"30Jan Feb12 Mar23 4Apr May09 11Jun";
  foreach (Match m in r.Matches(input))
  {
    Console.WriteLine("{0} {1}", m.Groups["MONTH"], m.Groups["DAY"]);
  }
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在.NET中,命名组的存在对非命名组的排序没有影响.命名组具有分配给它们的编号,但这些编号最后一个非命名组之后开始.(我知道这看起来很复杂,但有充分的理由这样做.)

通常,您希望避免将命名和非命名捕获组一起使用,尤其是在使用反向引用时,但我认为这种情况可能是合法的异常.

  • @Alan:嘿,八月怎么样?8 ^) (2认同)
  • 八月对于正则表达式来说太热了。:-/ (2认同)
  • 有没有办法强制每个组匹配 0 次或 1 次? (2认同)

Tim*_*Tim 5

您可以将regex片段存储在变量中,并执行以下操作:

A=/* relevant regex pattern */
B=/* other regex pattern */
regex = X($A$B|$B$A)Y
Run Code Online (Sandbox Code Playgroud)

这样,您只需在自己的行上指定一次正则表达式,这样可以更容易维护.

旁注:你试图找到排列,这是好的,因为你只看了2个子目标.但是如果你想增加第三个(或第四个),你的正则表达式排列会急剧增长 - (abc | acb | bac | bca | cab | cba) - 或者更糟.如果你需要走下排列的道路,那么在stackoverflow上有一些很好的讨论.它用于字母排列,解决方案使用awk/bash/perl,但这至少为你提供了一个起点.