我遇到了关于原始字符串的令人困惑且看似矛盾的规则。考虑以下示例:
>>> text = 'm\n' >>> match = re.search('m\n', text) >>> print match.group() m >>> print text m
This works, which is fine.
>>> text = 'm\n' >>> match = re.search(r'm\n', text) >>> print match.group() m >>> print text m
Again, this works. But shouldn't this throw an error, because the raw string contains the characters m\n
and the actual text contains a newline?
>>> text = r'm\n'
>>> match = re.search(r'm\n', text)
>>> print match.group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> print text
m\n
令人惊讶的是,上面的代码抛出了一个错误,即使它们都是原始字符串。这意味着两者都只包含没有换行符的文本 m\n
。
>>> text = r'm\n'
>>> match = re.search(r'm\\n', text)
>>> print text
m\n
>>> print match.group()
m\n
以上的工作,令人惊讶。 为什么我必须在 re.search 中转义反斜杠,而不是在文本本身?
然后是带有没有特殊行为的普通字符的反斜杠:
>>> text = 'm\&'
>>> match = re.search('m\&', text)
>>> print text
m\&
>>> print match.group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
这不匹配,即使模式和字符串都缺少特殊字符。
在这种情况下,原始字符串的任何组合都不起作用(文本作为原始字符串,模式作为原始字符串,两者兼而有之)。
但是,考虑最后一个例子。在文本变量 'm\\&'
中转义不起作用,但在模式中转义有效。这与上面的行为相似——我觉得甚至更奇怪,考虑到 \&
对 Python 或 re:
>>> text = 'm\&'
>>> match = re.search(r'm\\&', text)
>>> print text
m\&
>>> print match.group()
m\&
我对原始字符串的理解是它们抑制了 python 中反斜杠的行为。对于正则表达式,这很重要,因为它允许 re.search 应用它自己的内部反斜杠行为,并防止与 Python 发生冲突。但是,在上述情况下,反斜杠实际上没有任何意义,我不确定为什么它看起来是必要的。更糟糕的是,我不明白为什么我需要为模式使用反斜杠,而不是文本,当我将两者都制作成原始字符串时,它似乎不起作用。
The docs在这方面不提供太多指导。他们专注于有明显问题的示例,例如 '\section'
,其中 \s
是一个元字符。寻找完整的答案以防止出现此类意外行为。
最佳答案
在常规 Python 字符串 'm\n'
中,\n
表示单个换行符,而在原始字符串 r'm\n'
\
和 n
只是他们自己。到目前为止,就这么简单。
如果将字符串 'm\n'
作为模式传递给 re.search()
,则传递的是两个字符的字符串( m
后跟换行符),re
会很乐意为您找到该双字符字符串的实例。
如果您传递三个字符的字符串 r'm\n'
,re
模块本身 将解释这两个字符 \
n
具有特殊含义“匹配换行符”,因此整个模式意味着“匹配 m
后跟换行符”,只是和以前一样。
在您的第三个示例中,由于字符串 r'm\n'
不包含换行符,因此没有匹配项:
>>> text = r'm\n'
>>> match = re.search(r'm\n', text)
>>> print(match)
None
使用模式 r'm\\n'
,您将两个实际的反斜杠传递给 re.search()
,re
模块本身 将双反斜杠解释为“匹配单个反斜杠字符”。
在 'm\&'
的情况下,发生了一些稍微不同的事情。 Python 将反斜杠视为常规字符,因为它不是转义序列的一部分。另一方面,re
简单地丢弃了 \
,因此模式实际上是 m&
。通过针对 'm&'
测试模式,您可以看到这是真的:
>>> re.search('m\&', 'm&').group()
'm&'
和以前一样,双反斜杠告诉 re
搜索实际的反斜杠字符:
>>> re.search(r'm\\&', 'm\&').group()
'm\\&'
... 为了让事情变得更加困惑,单个反斜杠由 Python 加倍表示。你可以通过打印看到它实际上是一个反斜杠:
>>> print(re.search(r'm\\&', 'm\&').group())
m\&
关于python - 原始字符串、Python 和 re,普通字符与特殊字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41067866/