为什么我的 r'string' 正则表达式能匹配但 'string' 不能?

9 投票
4 回答
5644 浏览
提问于 2025-04-16 11:18

在Python中,正则表达式的工作方式让我感到非常困惑,每过一秒我就越发生气。我的问题是:

我明白这个代码会有结果:

re.search(r'\bmi\b', 'grand rapids, mi 49505)

而这个代码就没有结果:

re.search('\bmi\b', 'grand rapids, mi 49505)

这没关系,我能理解这一点。现在,我有一个正则表达式是这样生成的:

regex = '|'.join(['\b' + str(state) + '\b' for state in states])

如果我现在执行 re.search(regex, 'grand rapids, mi 49505'),它会失败,原因和我第二个 search() 示例失败的原因是一样的。

我的问题是:有没有办法实现我想做的事情?

相关问题:

4 个回答

2

关键在于理解'\b'和r'\b'之间的区别。在IDLE中输入这两个时,会得到这样的输出:

>>> '\b'
'\x08'
>>> r'\b'
'\\b'

所以每当你在正则表达式中输入反斜杠时,都应该用原始字符串的方式来处理它。

4

解决方案就是你在上面例子中自己用的:原始字符串。

regex = '|'.join(r'\b' + str(state) + r'\b' for state in states)

(注意,我还去掉了多余的括号,把列表推导式变成了生成器表达式。)

14

答案本身

regex = '|'.join([r'\b' + str(state) + r'\b' for state in states])

这里的原因是,'r'前缀告诉Python不要分析你传给它的字符串。如果你不在字符串前加'r',Python会试图把任何以'\'开头的字符变成特殊字符,这样你就可以轻松输入换行符(\n)、制表符(\t)等。

当你写'\b'时,你是在告诉Python创建一个字符串,分析它,并把'\b'转换成'退格',而当你写r'\b'时,Python只是把'\'和'b'存起来,这正是你在正则表达式中想要的。使用正则表达式模式时,始终使用'r'。

'r'这种写法叫做'原始字符串',但这有点误导,因为在Python内部并没有真正的原始字符串。你可以把它看作是一种告诉Python不要太聪明的方式。

在Python 3.0之前,还有另一种写法u'string',它告诉Python把字符串存储为unicode。你可以把两者结合起来:ur"é\n"会把"\bé"存储为unicode,而u"é\n"会存储"é"然后是一个换行。

一些改进你代码的方法:

regex = '|'.join(r'\b' + str(state) + r'\b' for state in states)

去掉多余的[]。这告诉Python不要把你生成的值列表存储在内存中。我们可以这样做,因为你并不打算重用你创建的列表,因为你直接在join()中使用它,而没有其他地方用到。

regex = '|'.join(r'\b%s\b' % state for state in states)

这样会自动处理字符串转换,而且更简洁。格式化字符串时,想想% 操作符

如果州包含邮政编码的列表,那么应该把它们存储为字符串,而不是整数。在这种情况下,你可以省略类型转换,进一步简化:

regex = r'\b%s\b' % r'\b|\b'.join(states)

最终,你可能根本不需要正则表达式。如果你只关心检查某个邮政编码是否在给定的字符串中,你可以直接使用in(检查某个项目是否在可迭代对象中,比如一个字符串是否在列表中):

matches = [s for s in states if s in 'grand rapids, mi 49505']

最后一句话

我理解你在学习新语言时可能会感到沮丧,但请花时间给你的问题起个合适的标题。在这个网站上,标题应该以问号结尾,并提供关于问题的具体细节。

撰写回答