具有多个可选组的正则表达式

时间:2014-12-30 19:14:35

标签: regex

我进行了搜索,但找不到合适的解决方案。我正在为Excel文件的标题格式设置正则表达式。这些使用& -commands用于格式化页眉和页脚,然后左,中,右标题简单地连接在一起:

(ECMA规范中的¶18.3.1.39)

&L&"Lucida Grande,Standard"&K000000Left top&C&"Lucida Grande,Standard"&K000000Middle top&R&"Lucida Grande,Standard"&K000000Right top

所有三个部分都是可选的。根据我读到的关于使组可选的内容,我提出了以下正则表达式(Python风格):

re.compile(r"""
(?P<left>&L.+?)
(?P<center>&C.+?)
(?P<right>&R.+?)$
""", re.VERBOSE)

但它失败的是一个只包含一部分&Ltest header的简单字符串。我想我理解了潜在的问题 - 缺少可选组的模式会影响其他模式 - 但不会影响语法,或者更确切地说,当缺少可选组时会发生什么。

2 个答案:

答案 0 :(得分:1)

尝试

^(?:.*?(?P<left>&L.[^&]*))?(?:.*?(?P<center>&C.[^&]*))?(?:.*?(?P<right>&R.[^&]*))?.*$

regex101 demo.


left群组的解释(centerright几乎相同):

(?:
    .*? # consume any preceding text
    (?P<left> # then capture...
        &L # "&L" literally
        . # the character after that
        [^&]* # and then everything up to the next "&" character
    )
)? # and make the whole thing optional.

P.S。:您的模式没有任何组可选。您应该在小组之后放置? ,例如(?P<left>&L.+)?


更新

由于这些组不应该以下一个&字符结束,您可以尝试使用该模式

(?P<left>&L.+?)?(?P<center>&C.+?)?(?P<right>&R.+?)?$

代替。我所做的就是通过添加?使所有组成为可选组,并通过将锚$放在最后来强制模式使用整个字符串。

regex101 demo.

更新(?:&L(?P<left>.+?))?(?:&C(?P<center>.+?))?(?:&R(?P<right>.+?))?$无法捕获&L&C&R位。

答案 1 :(得分:1)

您可以使用与left/center/right匹配的正则表达式以及一系列替换 条件用于匹配部件,而不管它们在行中出现的顺序 这样就可以匹配1,2或3个。

已更新

修改以匹配每个部分直到下一部分(如果它在那里) 基于此处有关条件的信息 - &gt; http://www.rexegg.com/regex-conditionals.html

如果它的python / PCRE应该可以工作:

(?:(?:[^&]|&[\S\s])*?(?:&L(?P<left>(?(left)(?!))(?:[^&]|&[^LCR])*)|&C(?P<center>(?(center)(?!))(?:[^&]|&[^LCR])*)|&R(?P<right>(?(right)(?!))(?:[^&]|&[^LCR])*))){1,3}  

如果是Perl / PCRE,这可行:

  # (?:(?:[^&]|&[\S\s])*?(?:&L(?<left>(?(<left>)(?!))(?:[^&]|&[^LCR])*)|&C(?<center>(?(<center>)(?!))(?:[^&]|&[^LCR])*)|&R(?<right>(?(<right>)(?!))(?:[^&]|&[^LCR])*))){1,3}

 (?:
      (?: [^&] | & [\S\s] )*?       # Get all possible quoted &&
                                    # even &[LCR] if needed
      (?:                           # Get one of   &L or &C or &R
           &L
           (?<left>                      # (1), Left
                (?(<left>)
                     (?!)                          # Allow only 1 left
                )
                (?: [^&] | & [^LCR] )*        # Get all possible quoted && up to but not &[LCR]
           )
        |  
           &C
           (?<center>                    # (2), Center
                (?(<center>)
                     (?!)                          # Allow only 1 center
                )
                (?: [^&] | & [^LCR] )*
           )
        |  
           &R
           (?<right>                     # (3), Right
                (?(<right>)
                     (?!)                          # Allow only 1 right
                )
                (?: [^&] | & [^LCR] )*
           )
      )
 ){1,3}                        # Do 1 to 3 times

输出:

 **  Grp 0 -  ( pos 0 , len 132 ) 
&L&"Lucida Grande,Standard"&K000000Left top&C&"Lucida Grande,Standard"&K000000Middle top&R&"Lucida Grande,Standard"&K000000Right top  
 **  Grp 1 -  ( pos 2 , len 41 ) 
&"Lucida Grande,Standard"&K000000Left top  
 **  Grp 2 -  ( pos 45 , len 43 ) 
&"Lucida Grande,Standard"&K000000Middle top  
 **  Grp 3 -  ( pos 90 , len 42 ) 
&"Lucida Grande,Standard"&K000000Right top