正则表达式以任何顺序捕获命名组

时间:2015-04-08 20:53:25

标签: python regex

我有一个场景,我需要使用一次调用Python的re.sub()来查找和替换字符串中的项目。如果这种约束听起来很人为,那么只要将其视为心理练习,但要知道这是我必须要处理的现实约束。

我希望匹配并替换以下任一行:

foo -some-arg -o %output %input
foo %input -other-random-arg=baz -o %output

用这个:

bar %output %input.out

文件名%input和%output可以是匹配[a-zA-Z0-9._-]+的任何内容,但始终以%

开头

我提出了这种替代方法,这种方法并不奏效。

    r'''(?x)                     # Begin verbose regex
        foo[ ]                   # foo and a space
        (?=.*?-o[ ]                  # Lookahead for the first occurrence of -o
            (?P<a>%\S+\b)                # Output filename -> Group 'a'
        )
        (?=.*?                       # Lookahead from the same place as the first lookahead
                                     # so the two filenames can match in any order.
            (?!-o[ ]%\S+\b)              # Do not match the output file
            (?P<b>%\S+\b)                # Any filename -> Group 'b'
        ).*                      # Match anything ''',
    r'bar \g<b> \g<a>.out'       # Replacement

我经常最终将两个文件名中的一个重复两次,如:

bar %output %output.out

有没有办法按照它们出现的顺序命名捕获两个文件名?似乎如果我可以在匹配其中一个前瞻时推进正则表达式引擎的指针,我可以做到这一点。

1 个答案:

答案 0 :(得分:2)

由于所有参数都以破折号开头,并且由于输入和输出总是存在一次,因此您可以使用忽略该顺序的这种模式:

foo(?: -o (?P<output>\S+)| -\S+| (?P<input>\S+))+

和替换

bar \1 \2.out

注意:如果要处理包含空格的文件名(在命令行中转义),则需要将\S+更改为(?:[^\s\\]+(?:\\.[^\s\\]*)*|[^\s\\]*(?:\\.[^\s\\]*)+) (仅用于输入和输出)