1、使用字符串的方法
有时使用 re
模块是个错误!如果你匹配一个固定的字符串或者单个字符类,并且你没有使用re
的任何标志(像 IGNORECASE 标志),那么就没有必要使用正则表达式了。字符串有一些方法是对固定字符串进行操作的,并且它们通常比较快。
举个例子,例如你想把字符串中所有的dead
替换成 word
,你会想到使用正则表达式的 re.sub()
方法来实现,但这么简单的替换,还是考虑直接使用字符串的replace()
方法吧。但有一点你需要注意,就是 replace()
会在单词里边进行替换,像 swordfish
会变成 sdeedfish
,这显然不是你想要的!replace()
没办法识别单词的边界,因此你才来考虑使用正则表达式。只需要将 RE 的模式写成 \bword\b
即可胜任此任务。
另一个常见的情况是从一个字符串中删除单个字符或者用另一个字符替代它。你也许会想到用 re.sub('\n', ' ', S)
这样的正则表达式来实现,但其实字符的translate()
方法完全能够胜任这个任务,并且比任何正则表达式操作起来更快些。
简而言之,在使用re
模块之前,先考虑一下你的问题是否可以用更快速、简单的字符串自带方法来解决。
2、match() VS search()
match()
函数只会检查 RE 是否在字符串的开始处匹配,而 search()
会遍历整个字符串搜索匹配的内容。记住这一区别很重要。再次强调一下,match()
只会报告一次成功的匹配,并且匹配的位置必须是从字符串的第一个字符开始:
>>> print(re.match('super', 'superstition').span())
(0, 5)
>>> print(re.match('super', 'insuperable'))
None
另一方面,search() 函数将遍历整个字符串,并报告它找到的第一个匹配:
>>> print(re.search('super', 'superstition').span())
(0, 5)
>>> print(re.search('super', 'insuperable').span())
(2, 7)
>>> print(re.search('super', 'insuperableaaaaasuper').span())
(2, 7)
3、贪婪 VS 非贪婪
当重复一个正则表达式时,如果使用 a*,那么结果是尽可能多地去匹配。当你尝试匹配一对对称的定界符,例如 HTML 标志中的尖括号,默认的贪婪模式会使得你很困扰。
我们来看下例子:
>>> s = 'Title '
>>> len(s)
32
>>> print(re.match('<.*>', s).span())
(0, 32)
>>> print(re.match('<.*>', s).group())
Title
RE 匹配在 的
<
后,.*
消耗掉字符串的剩余部分。由于正则表达式默认是贪婪的原因,RE 必须从字符串的尾部一个字符一个字符地回溯,直到找到匹配的 >
。大家看到,按照这种方法,最后找到匹配内容竟是 的
<
开始,到 的
>
结束。显然这不是你想要的结果。
在这种情况下,解决方案是使用非贪婪的限定符 *?、+?、?? 或 {m,n}?
,尽可能地匹配小的文本。
>>> print(re.match('<.*?>', s).group())
在上边的例子中,>
在第一个<
被匹配后立刻尝试匹配,如果失败,匹配引擎前进一步,尝试下一个字符,直到第一次匹配 >
,这样就得到了我们想要的结果。
注意,使用正则表达式分析 HTML 和 XML 是很痛苦的。当你编写一个正则表达式去处理所有可能的情况时,你会发现 HTML 和 XML 总会打破你的“规则”,这让你很头疼......像这样的话,建议使用 HTML 和 XML 解析器来处理更合适。
4、使用 re.VERBOSE
现在你应该意识到了,正则表达式的表示非常紧凑。这也带来了一个问题,就是不好阅读。中等复杂的正则表达式可能包含许多反斜杠、圆括号和元字符,以至于难以读懂。
在这些 REs 中,当编译正则表达式时指定re.VERBOSE
标志是非常有帮助的。因为它允许你可以编辑正则表达式的格式,使之更清楚。
re.VERBOSE
标志有几个作用。在正则表达式中不在字符类中的空白字符将被忽略。这就意味着像 I love FishC
这样的表达式和可读性较差的IloveFishC
相同。但 [a b]
将匹配字符 'a'、'b' 或 ' '
;另外,你也可以把注释放到 RE 中,注释是从#
开始到下一行。当使用三引号字符串时,会使得 REs 的格式更整洁:
pat = re.compile(r"""
\s* # Skip leading whitespace
(?P[^:]+) # Header name
\s* : # Whitespace, and a colon
(?P.*?) # The header's value -- *? used to
# lose the following trailing whitespace
\s*$ # Trailing whitespace to end-of-line
""", re.VERBOSE)
同样的内容,下边这个要难读得多:
pat = re.compile(r"\s*(?P[^:]+)\s*:(?P.*?)\s*$")
https://fishc.com.cn/thread-57438-1-1.html