用Python正则表达式匹配多行make变量赋值

2 投票
4 回答
1393 浏览
提问于 2025-04-16 21:05

我正在尝试从一个多行的变量赋值中提取出多行的值。下面这个测试案例在输入字符串中找不到匹配的内容,我必须承认我搞不清楚为什么会这样。如果能帮我让这个示例代码在标准输出上打印出 "a \ b",我将非常感激。

#!/usr/bin/env python                                                                                                 

def test():
    s = r"""                                                                                                          
FOO=a \                                                                                                               
  b                                                                                                                   
"""
    import re
    print type(s),s
    regex = re.compile(r'^FOO=(.+)(?<!\\)$', re.M)
    m = regex.search(s)
    print m.group(1)

if __name__ == '__main__':
    test()

4 个回答

0

你的示例文本中有很多空格,包括反斜杠后面。我想这不是你想要的,因为反斜杠的作用是用来转义换行符,换行符通常表示输入的结束。

不过,反斜杠也可以用来转义其他字符,包括反斜杠本身。如果一个值恰好以反斜杠结尾,在makefile中会显示为两个反斜杠。你的正则表达式中的“向后查找”会“看到”第二个反斜杠,并错误地将其视为行的继续。

如果你想添加另一个向后查找来检查反斜杠是否被转义,我建议你别这样做。这种方法已经讨论过很多次,向后查找的方式无法奏效。你需要的是像这样的东西:

regex = re.compile(r'^FOO=([^\n\\]*(?:\\.[^\n\\]*)*)$', re.M | re.S)

在ideone上查看效果

第一个 [^\n\\]* 会尽可能多地匹配非换行和非反斜杠的字符,然后将控制权交给下一部分。如果字符串的末尾还没到,它会尝试匹配一个反斜杠后面跟着任意字符(包括换行符,因为有 re.S 修饰符),然后再跟一些“正常”的字符。它会这样循环下去,直到(假设输入是有效的)遇到一个未转义的换行符或输入的末尾。

虽然是 re.S 修饰符让点号可以匹配换行符,但 re.M 修饰符也是必要的;它让 ^ 匹配行的开头,$ 匹配行的结尾,正如 @stema 所解释的那样。

1

你的问题是,默认情况下,.这个符号是无法匹配换行符的。如果你开启“Dotall”模式,它就可以工作了。

regex = re.compile(r'^FOO=(.+)(?<!\\)$', re.M | re.S)

你可以通过使用re.S来实现这个功能。

这样输出的结果将会是

a \

 b

你的模式确实可以匹配包含换行符的内容。

我不太确定你想用多行模式re.M达到什么效果。这个模式会让^$分别匹配行的开始和结束。我想你可以把它去掉。

我也不太明白你想用负向前瞻(?<!\\)实现什么,建议你明确一下你期望的输出结果。(你是想去掉“\”和换行符之间的内容吗?)

2

re.M代表的是re.MULTILINE,这个选项和点号(.)的含义没有关系,它主要影响的是开头(^)和结尾($)的符号。

如果你想让点号(.)也能匹配换行符(\n),你需要使用re.DOTALL这个选项。

def test():
    s = r"""    

FOO=a \    

  b

  """
    import re
    print repr(s)
    print '---------------------'
    regex = re.compile(r'^FOO=(.+)(?<!\\)$', re.M)
    print regex.search(s).group(1)
    print '---------------------'
    regex = re.compile(r'^FOO=(.+)(?<!\\)$', re.M|re.DOTALL)
    print regex.search(s).group(1)

test()

结果

'    \n\nFOO=a \\    \n\n  b\n\n  '
---------------------
a \    
-----
'a \\    '
---------------------
a \    

  b


-----
'a \\    \n\n  b\n\n  '

撰写回答