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

时间:2010-04-08 00:48:46

标签: regex

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

XABY
XBAY

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

X(AB|BA)Y

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

由于

4 个答案:

答案 0 :(得分:21)

X(?:A()|B()){2}\1\2Y

基本上,你使用一个空的捕获组来检查每个项目是否匹配,然后反向引用确保所有项目都已被检查。

请注意,这依赖于未记录的正则表达式行为,所以不能保证它会在您的正则表达式中起作用 - 如果确实如此,则无法保证它将继续以此方式工作味道进化。但据我所知,它适用于支持反向引用的每种风格。 (编辑:它在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"]);
  }

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

通常你想避免一起使用命名和非命名的捕获组,特别是如果你正在使用反向引用,但我认为这种情况可能是合法的例外。

答案 1 :(得分:5)

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

A=/* relevant regex pattern */
B=/* other regex pattern */
regex = X($A$B|$B$A)Y

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

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

答案 2 :(得分:1)

试试这个

X((A|B){2})Y

答案 3 :(得分:0)

如果有多个字符串,其中包含任何类型的字符,那么您最好使用:

X(.)+Y

只有数字

X([0-9])+Y

只有字母

X([a-zA-Z])+Y

字母和数字

X([a-zA-Z][0-9])+Y