使用可选分隔符捕获Perl正则表达式

时间:2017-03-07 00:09:33

标签: regex perl

我正在尝试使用perl regex在模板模式上过滤Wikipedia转储:

{{tl|a|b|c}}

我想捕获ab,其中abc等可以是任何一组UTF-8字符,不包括|}。最终的}}'之前可能会有未知数量的集合,但总会至少有两个(ab)。所以你也可以得到:

{{tl|a|b}}

{{tl|a|b|c|d}}

作为一名正则表达式新手,我首先想到尝试/\{\{tl\|(.+?)\|(.+?)\|?\}\}/

这给出了正确的完全匹配和第一次捕获,但在第二次捕获时失败,返回b|c|d因为它找不到|}。我需要告诉它在|}之间寻找某些内容,但只有在找到|时才会这样做。似乎应该有一个解决这个问题的简单方法,但我会陷入困境。

2 个答案:

答案 0 :(得分:0)

你可以这样试试\{\{[^|}]*(?:\|[^|}]*)*\}\}
但不会得到捕获。

解释

 \{\{         # Open {{
 [^|}]*       # Optional, not | or }
 (?:          # Group start
      \|           # |
      [^|}]*       # Optional not | or }
 )*           # Group end, optional 0 to many times
 \}\}         # Close }}

或者,使用\G锚点并在第1组中获取结果

(?:\G(?!\A)|\{\{)([^|}]*)(?=(?:\|[^|}]*)*\}\})(?:\||\}\})

 (?:
      \G 
      (?! \A )
   |  
      \{\{                    # Open {{
 )

 ( [^|}]* )              # (1), Data

 (?=                     # Assert this is valid
      (?:
           \|                      # |
           [^|}]*                  # Optional not | or }
      )*                      # Group end, optional 0 to many times
      \}\}                    # Close }}
 )                       # End Assert

 (?:
      \|                      # Consume |
   |                        # or
      \}\}                    # Consume Close }}
 )

答案 1 :(得分:0)

好的,我明白了。答案来自于使用(?:pattern)进行“群集,而不是捕获”群组。 (来自perldoc)。使用此功能,您可以创建我们可以检查而无需捕获的组 - 在这种情况下,可以选择}}|c|d}}。所以,作为一个正则表达式,答案是:

/\{\{tl\|([^\|]+?)\|(.+?)(?:\}\}|\|[^\}]+?\}\})/

第一部分与我之前的情况类似,/\{\{tl\|标识模板的第一部分,([^\|]+?)\|标识第一个捕获并停止|。下一部分设置第二个捕获(.+?),它由\}\}构造内部\|[^\}]+?\}\} OR (?: )的选择分隔。

希望这有助于其他人!