7.5. 松散正则表达式

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

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

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

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

>>> pattern = """
    ^                   # beginning of string
    M{0,3}              # thousands - 0 to 3 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, 'MMMDCCCLXXXVIII', re.VERBOSE)  3
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'M')                            4
1 当使用松散正则表达式时,最重要的一件事情就是:必须传递一个额外的参数 re.VERBOSE,该参数是定义在 re 模块中的一个常量,标志着待匹配的正则表达式是一个松散正则表达式。正如你看到的,这个模式中,有很多空格 (所有的空格都被忽略),和几个注释 (所有的注释也被忽略)。如果忽略所有的空格和注释,它就和前面章节里的正则表达式完全相同,但是具有更好的可读性。
2 这个模式匹配字符串的开始,接着匹配三个可选 M 字符中的一个,接着匹配 CM,接着是字符 L 和三个可选 X 字符的所有字符,接着是 IX,然后是字符串的结尾。
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 默认每一个正则表达式都是紧凑类型的,除非你显式地标明一个正则表达式为松散类型。