7.5. 松散正则表达式

Python

7.5. 松散正则表达式

迄今为止,你只是处理过被我称之为“紧凑”类型的正则表达式。正如你曾看到的,它们难以阅读,即使你清楚正则表达式的含义,你也不能保证六个月以后你还能理解它。你真正所需的就是利用内联文档(inline documentation)。

Python 允许用户利用所谓的 松散正则表达式来完成这个任务。一个松散正则表达式和一个紧凑正则表达式主要区别表现在两个方面:

  • 忽略空白符。空格符,制表符,回车符不匹配它们自身,他们根本不参与匹配。(如果你想在松散正则表达式中匹配一个空格符,你必须在它前面添加一个反斜线符号对他进行转义)
  • 忽略注释。在松散正则表达式中的注释和在普通Python代码中的一样:开始于一个#符号,结束于行尾。这种情况下,采用在一个多行字符串中注释,而不是在源代码中注释,他们以相同的方式工作。

用一个例子可以解释的更清楚。让我们重新来看前面的紧凑正则表达式,利用松散正则表达式重新表达。下面的例子显示实现方法。

例 7.9. 带有内联注释(Inline Comments)的正则表达式

>>> pattern = """
    ^                   # beginning of string
    M{0,4}              # thousands - 0 to 4 M's
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                        #            or 500-800 (D, followed by 0 to 3 C's)
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                        #        or 50-80 (L, followed by 0 to 3 X's)
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                        #        or 5-8 (V, followed by 0 to 3 I's)
    $                   # end of string
    """
>>> re.search(pattern, 'M', re.VERBOSE)                1
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXXIX', re.VERBOSE)        2
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMMMDCCCLXXXVIII', re.VERBOSE) 3
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'M')                            4
1 当使用松散正则表达式是,请记住最重要的一件事情就是:必须传递另外一个参数re.VERBOSE,该参数是定义在re 模块中的一个常量,标志着待匹配的正则表达式是一个松散正则表达式。正如你看到的,这个模式中,有很多空格(所有的空格都被忽略),和几个注释(所有的注释也被忽略)。一旦你忽略所有的空格和注释,就和前面章节里的正则表达式完全相同,但是它具有更好的可读性。
2 这个模式匹配字符串的开始,接着匹配四个可选M字符中的一个,接着匹配CM, 接着是字符L和三个可选X字符的所有字符,接着是IX,然后是字符串的结尾ie。
3 这个模式匹配字符串的开始,接着是四个可选的M字符的所有字符,接着匹配 D?C{0,3} ,此处为一个字符D和三个可选 C字符中所有字符,接着匹配L?X{0,3},此处为一个L字符和三个可选X字符中所有字符,接着匹配V?I{0,3},此处为一个字符V和三个可选I字符中所有字符,接着匹配字符串的结尾。
4 这个没有匹配。为什么呢?因为没有re.VERBOSE标记,所以re.search函数把模式作为一个紧凑正则表达式进行匹配。Python 不能自动检测一个正则表达式是为松散类型还是紧凑类型。Python 默认每一个正则表达式都是紧凑类型的,除非你显式的标明一个正则表达式为松散类型。
<< 使用{n,m} 语法
 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 

个案研究: 解析电话号码 >>