python - 原始字符串、Python 和 re,普通字符与特殊字符

标签 python regex escaping backslash

我遇到了关于原始字符串的令人困惑且看似矛盾的规则。考虑以下示例:

>>> 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/

相关文章:

escaping - 如何在 gnu-parallel 中转义大括号

c# - 使用正则表达式在 C# 中查找带有转义引号的引用字符串

python - 导入表达式的差异?

python - 应用列范围函数时,如何从数据框中的不同列中获取某些值?

python - 使用 Flask 框架登录

python - Django 静态文件在 DEBUG=True 和 `collectstatic` 之后不一致

javascript - JavaScript 中的正则表达式 - 未正确过滤

java - 匹配器在匹配后抛出 IllegalStateException

Javascript 正则表达式 - 括号引号

C++11 regex_error - 为什么? (代码 : 2)