【问题标题】:why python2's re module can't identify the u'®' character为什么python2的re模块不能识别u'®'字符
【发布时间】:2019-01-05 16:40:09
【问题描述】:

我有一个字符串,我想在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")

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

【问题讨论】:

  • 这不是你的问题,但你真的不应该尝试将 8 位字符串 "" 子转换为 Unicode 字符串 u"a™b®c"。为了做到这一点,Python 必须猜测你是要编码一个还是解码另一个,即使它碰巧猜对了,你仍然依赖于一些不明显的东西,并且让你的代码有点慢,无缘无故。
  • @abarnert 是的,你是对的,我应该使用u''
  • 这在我的带有 python 2.7.14 的 linux 机器上运行良好。我无法重现您的错误。
  • @HåkenLid 是的,这段代码在 Ubuntu 上完美运行,我的问题是 Linux 是另一个发行版
  • Python 2 确实没有更好的解决方案。您可以小心始终使用unicode 值(编码和解码尽可能靠近边缘),也许使用 PEP 484 类型提示评论表单加上 Mypy 以确保您不会搞砸并使用 str,永远不要在文字中使用 Unicode 字符等,但这仍然会很痛苦。如果有比 Python 2 更好的解决方案,Python 3 就不会存在。

标签: python regex windows python-2.7 python-unicode


【解决方案1】:

这里有两个问题。


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

在 Python 3 中,这很好,因为 re 模块将 \u 转义理解为 Unicode 字符,因此模式最终成为其中包含 U+2122U+00AE 的字符类,完全符合您的要求.但是在 Python 2 中,它没有,所以字符类最终变成了一堆无用的垃圾。

如果您将其更改为使用非原始字符串文字,则将解决该问题: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 不是同一个字符,因此没有匹配。 (您的第一个示例有效,因为您的搜索字符串 also 有不正确的\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 转义更好,但它会起作用。

【讨论】:

  • 根据您的建议,我在源代码中使用了它们,并且使用 unicode 可以正常工作。同时,我将正则表达式更新为u"[\u0099\u2122]",看看Python是否可以识别标记,如果控制台做了一些错误解释,结果显示Python仍然无法匹配,可能是因为我的控制台默认为ANSI ?总而言之,我认为你是对的,使用 Python 2 本身就是问题。
【解决方案2】:

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

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

【讨论】:

  • 我复制了您的代码,但它仍然无法在 Python 2.7.15 |Anaconda, Inc.| (default, May 1 2018, 18:37:09) [MSC v.1500 64 bit (AMD64)] on win32 上运行。它打印u'a?b?c'
  • @calvin 您在问题中的尝试和这个答案都适用于我的机器。我正在使用 Python 2.7.10 和 macOS HighSierra。可能与 Windows 的编码有关?
  • 这将在 Mac 上工作,但这只是因为 Mac 终端是 UTF-8。它不适用于 Windows。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-22
  • 2023-03-04
  • 1970-01-01
  • 2014-08-12
相关资源
最近更新 更多