代码之家  ›  专栏  ›  技术社区  ›  Colin Pickard

regex:使用包围括号作为分隔符,而忽略任何内括号

  •  0
  • Colin Pickard  · 技术社区  · 15 年前

    我已经构建了一个复杂的(对我来说)regex来解析一些文件名,它大体上可以工作,除了在括号内有额外的内容。

    (?'field'F[0-9]{1,4})(?'term'\(.*?\))(?'operator'_(OR|NOT|AND)_)?
    

    在下面的示例中,我需要在注释后获取组,但在第3个示例中,我正在获取 ((brackets) 而不是 ((brackets)are valid) .

    对于我的生活,我不知道如何扩展它来寻找最后一个等级。

    C:\Temp\[DB_3][DT_2][F30(green)].vsl // F30 (green)
    C:\Temp\[DB_3][DT_2][F21(red)_OR_F21(blue)_NOT_F21(pink)].vsl // F21 (red) _OR_ OR
    C:\Temp\[DB_3][DT_2][F21((brackets)are valid)].vsl // F21 ((brackets)are valid)
    C:\Temp\[DB_3][DT_2][F21(any old brackets)))))are valid)].vsl // F21 (any old brackets)))))are valid)
    C:\Temp\[DB_3][DT_2][F21(brackets))))))_OR_F21(blue)].vsl // F21 (brackets)))))) _OR_ OR
    

    谢谢


    更新:我正在使用regexr进行实验,然后在C中实现,如下所示:

    Regex r = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
    
    foreach(Match m in r.Matches(foo))
    {
        //etc
    }
    

    更新2:我不需要匹配括号。在一组括号内可以是任何数据,我只需要它以外部括号结束。


    更新3:

    另一种尝试是,使用额外的括号(示例3和4),但仍然无法拆分额外的术语(示例5),但不幸的是,包括终止 ] 在小组中。我怎样才能让它搜索(但不包括) )_ )] 作为分隔符,但只包括括号?

    (?'field'F[0-9]{1,4})(?'term'\(.*?\)[\]])(?'operator'_(OR|NOT|AND)_)?
    

    最后一个更新:我已经决定不值得花这么多精力来解析这种愚蠢的格式,所以我将放弃对它的支持,用我的时间做一些更有成效的事情。谢谢大家的帮助,我现在看到了光明!

    5 回复  |  直到 15 年前
        1
  •  2
  •   Bart Kiers    15 年前

    与regex匹配的嵌套括号是 a) 不可能*,或 b) 导致无法维护的regex。

    如果你只是想匹配第一个 ( 直到最后 ) (不检查左括号和右括号是否正确匹配),然后移除 ? 之后 .*? .

    *这取决于你用的是什么样的雷吉司口味。

        2
  •  2
  •   Benj    15 年前

    嗯,这在大多数regex引擎中通常是不可能的。尽管在Perl中是可能的:

    PerlMonks

    通过使用递归regexp:

    use strict;
    use warnings;
    
    my $textInner =
      '(outer(inner(most "this (shouldn\'t match)" inner)))';
    my $innerRe;
    my $idx=0;
    my(@match);
    
    $innerRe = qr/
                    \(
                    (
                       (?:
                          [^()"]+
                       |
                          "[^"]*"
                       |
                          (??{$innerRe})
                       )*
                    )
                    \)(?{$match[$idx++]=$1;})
                 /sx;
    
    $textInner =~ /^$innerRe/g;
    
    print "inner: $match[0]\n";
    

    在大多数regex引擎中也可以这样做,前提是您希望在固定的支架嵌套深度内这样做。不久前,我用Java编写了一个可以匹配到6深括号的正则表达式。

    下面是我的Java函数,用于生成正则表达式:

    public static String generateParensMatchStr(int depth, char openParen, char closeParen)
    {
        if (depth == 0)
            return ".*?";
        else
            return "(?:\\" + openParen + generateParensMatchStr(depth - 1, openParen, closeParen) + "\\" +closeParen + "|.*?)+?";
    }
    
        3
  •  2
  •   YOU    15 年前

    这是我在python中的另一个测试结果

    x="""C:\Temp\[DB_3][DT_2][F30(green)].vsl // F30 (green)
    C:\Temp\[DB_3][DT_2][F21(red)_OR_F21(blue)_NOT_F21(pink)].vsl // F21 (red) _OR_ OR
    C:\Temp\[DB_3][DT_2][F21((brackets)are valid)].vsl // F21 ((brackets)are valid)
    C:\Temp\[DB_3][DT_2][F21(any old brackets)))))are valid)].vsl // F21 (any old brackets)))))are valid)
    C:\Temp\[DB_3][DT_2][F21(brackets))))))_OR_F21(blue)].vsl // F21 (brackets)))))) _OR_ OR"""
    x=re.sub("//.*","",x)
    x=re.sub("(_(OR|NOT|AND)_).*?]"," \\1 \\2]",x)
    x=re.findall("(?:F[0-9]{1,4}\(.*\).*(?=]))",x)
    for x in x:print x
    

    这给了

    F30(green)
    F21(red) _OR_ OR
    F21((brackets)are valid)
    F21(any old brackets)))))are valid)
    F21(brackets)))))) _OR_ OR
    

    这会达到你预期的结果吗?

        4
  •  1
  •   YOU    15 年前
    re.findall("((?:F[0-9]{1,4}\(.*\))(?:_(?:OR|NOT|AND)_)?)+?",YOURTEXT)
    

    呆子

    ['F30(green)', 'F21(red)_OR_F21(blue)_NOT_F21(pink)', 'F21((brackets)are valid)', 'F21(any old brackets)))))are valid)', 'F21(brackets))))))_OR_F21(blue)']
    

    在巨蟒中,你认为呢?

        5
  •  1
  •   Matteo Riva    15 年前

    试试这个

    /(F[0-9]{1,4})(\([^_\]]+\))(?:_(OR|NOT|AND)_)?/

    用PHP测试,似乎给出了预期的结果(只要圆括号内的字符串不包含 _ ] )