为什么我的 r'string' 正则表达式能匹配但 'string' 不能?
在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 个回答
关键在于理解'\b'和r'\b'之间的区别。在IDLE中输入这两个时,会得到这样的输出:
>>> '\b'
'\x08'
>>> r'\b'
'\\b'
所以每当你在正则表达式中输入反斜杠时,都应该用原始字符串的方式来处理它。
解决方案就是你在上面例子中自己用的:原始字符串。
regex = '|'.join(r'\b' + str(state) + r'\b' for state in states)
(注意,我还去掉了多余的括号,把列表推导式变成了生成器表达式。)
答案本身
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']
最后一句话
我理解你在学习新语言时可能会感到沮丧,但请花时间给你的问题起个合适的标题。在这个网站上,标题应该以问号结尾,并提供关于问题的具体细节。