为什么 python2 的 re 模块无法识别 u'®' 字符

why python2's re module can't identify the u'®' character

我得到了一个字符串,我想在 Python2 中 re.sub 这个字符串,所以我尝试了下面的语句,它起作用了

>>> import re
>>> re.sub(u"[™®]", "", u"a™b®c")
'abc'

但是当我尝试以下语句时,它在 Windows 10 (Python 2.7.15 |Anaconda, Inc.|(默认,2018 年 5 月 1 日,18:37:09) [MSC v.1500 64 位 (AMD64)] 在 win32 上。

>>> re.sub(ur"[\u2122\u00ae]", "", u"a™b®c")
u'a?b?c'

我已经尝试了 Python and regular expression with Unicode 的解决方案,但它也没有用。

>>> myre = re.compile(ur'[\u2122\u00ae]', re.UNICODE)
>>> print myre.sub('', u"a™b®c")

为什么会发生这种情况,我该如何解决?

只需删除字符串前的 r 即可:

re.sub(u"[\u2122\u00ae]", "", u"a™b®c")

你这里有两个问题。


首先,原始字符串文字的全部意义在于它们不会将反斜杠转义视为反斜杠转义。所以,ur"[\u2122\u00ae]"字面意思就是字符[\u21

在 Python 3 中,这很好,因为 re 模块将 \u 转义理解为 Unicode 字符,所以模式最终成为 class 字符U+2122U+00AE 在里面,完全如你所愿。但在 Python 2 中,它没有,所以字符 class 最终变成了一团无用的垃圾。

如果将其更改为使用非原始字符串文字,将解决该问题:u"[\u2122\u00ae]"。当然,这会带来所有其他潜在问题,使人们首先想在正则表达式中使用原始字符串文字——但幸运的是,这里没有这些问题。


第二个问题是您在没有编码声明的情况下在 Unicode 文字中使用 Unicode 字符。同样,在 Python 3 中不是问题,但在 Python 2 中是问题。

当您键入 "a™b®c" 时,很有可能您输入的 Python 不是 \u2122 字符,而是 \u0099 字符。您的控制台可能位于类似 cp1252 的位置,因此当您键入或粘贴 时,它实际给出的 Python 是 U+0099,而不是 U+2122。当然,您的控制台也会 显示 错误,因此 U+0099 最终看起来像 。但是 Python 不知道发生了什么。它只是看到 U+0099 与 U+2122 不是同一个字符,因此没有匹配项。 (您的第一个示例有效,因为您的搜索字符串 有不正确的 \u0099,所以它恰好匹配。)

在源代码中,您可以通过添加一个编码声明来告诉 Python 您正在使用 cp1252,或者告诉您的编辑器在第一个文件中使用 UTF-8 而不是 cp1252 来解决这个问题地方。但是在交互式解释器中,你可以得到你的控制台想要的任何编码,而且没有地方可以放置编码声明。

真的,没有好的解决办法。

嗯,有:升级到Python 3。它存在的主要原因是让像这样的Unicode头痛消失,Python 2不到一年离生命结束还有一半,所以你真的想在今天 Python 2 中学习如何处理 Unicode 问题吗?

您还可以获得一个 UTF-8 终端(以及 Python 识别的终端)。这在 macOS 或最新的 Linux 发行版上是自动的;在 Windows 上,它要难得多,而且可能不是你想去这里的方式。

因此,唯一的选择就是永远不要在交互式解释器的 Unicode 文字中使用 Unicode 字符。同样,您 可以 在源代码中使用它们,但是以交互方式,您必须:

  • 使用反斜杠转义。
  • 使用非 Unicode 文字并在任何地方仔细解码它们。

我不确定 "a™b®c".decode('cp1252') 是否真的比 \u 转义更好,但它会起作用。