【问题标题】:encoding issue. Replace special character编码问题。替换特殊字符
【发布时间】:2017-06-03 00:53:54
【问题描述】:

我有一本像这样的字典:

{ u'Samstag & Sonntag': u'Ganztags ge\xf6ffnet', u'Freitag': u'18:00 & 22:00'}

现在我正在尝试将 \xf6 替换为 ö , 但尝试.replace('\xf6', 'ö') 会返回错误:

UnicodeDecodeError: 'ascii' 编解码器无法在位置解码字节 0xf6 0: 序数不在范围内(128)

我该如何解决这个问题?

【问题讨论】:

  • 这很可能是 Python2。但是,如果您标记您的问题或提及您正在使用的 Python 版本,那就太好了。因为Python2和Python3在解码部分差别很大。这个问题是因为默认情况下,unicode 字符串将使用 ASCII 解码进行解码,因为在您的脚本中使用了未定义的编码,并且您在替换调用中将 ASCII 替换为 ASCII。IIRC。
  • 您是如何在u'' 字符串中以...开头的\xf6 结尾的?
  • u'\xf6'u'ö' 完全相同:len(u'\xf6')==1; u'\xf6' == u'ö'
  • 这里的评论都疯了吗?你不需要更换任何东西! .replace(u'\xf6', u'ö') 是空操作。
  • 您使用的是什么操作系统?你的终端使用什么编码? print u'Ganztags ge\xf6ffnet' 在您的终端中显示什么?根据您的设置,您可能能够直接打印 Unicode 对象,否则您需要进行适当的编码,例如 print u'Ganztags ge\xf6ffnet'.encode('utf8')print u'Ganztags ge\xf6ffnet'.encode('latin1')

标签: python python-2.7


【解决方案1】:

现在编码是一个雷区,我可能不喜欢这个 - 如果是这样,请纠正我。

根据我多年来收集到的信息,除非您在脚本顶部定义了编码,否则 Python2 假定为 ASCII。主要是因为它是以这种方式编译的,或者操作系统/终端使用 ASCII 作为它的主要编码。

话虽如此,您在示例数据中看到的内容:

{ u'Samstag & Sonntag': u'Ganztags ge\xf6ffnet', u'Freitag': u'18:00 & 22:00'}

是 Unicode 字符串的 ASCII 表示。 Python 需要如何告诉您其中有一个 ö - 但它不能使用 ASCII,因为 öASCII table 中没有表示。

但是当您尝试使用以下方式替换它时:

x.replace('\xf6', 'ö')

您正在尝试查找一个名为 \xf6 的 ASCII 字符/字符串,它超出了 ASCII 可接受的字节范围,因此会引发异常。而你试图用另一个无效的 ASCII 字符替换它,这将导致同样的异常。

因此您会收到“'ascii' 编解码器无法解码字节...”消息。

您可以像这样进行 unicode 替换:

a = u'Ganztags ge\xf6ffnet'
a.replace(u'\xf6', u'ö')

这将告诉 Python 找到一个 unicode 字符串,并将其替换为另一个 unicode 字符串。
但是输出数据会导致上例中相同的结果,因为\xf6在unicode中是ö

您想要做的是将您的字符串编码成您想要使用的东西,例如 - UTF-8:

a.encode('UTF-8')
'Ganztags ge\xc3\xb6ffnet'

并将 UTF-8 定义为您的主要编码,方法是将其放在代码的顶部:

#!/usr/bin/python
# -*- coding: UTF-8

理论上,这应该会使您的应用程序更易于使用。
从那时起,您就可以使用 UTF-8 作为您的基本模型。

但据我所知,无法将您的表示形式转换为 ASCII ö,因为真的没有这样的事情。 Python 会以不同的方式为您执行这种编码魔法,让您相信“只写 ö”是可能的。

在 Python3 中,您遇到的大多数字符串要么是 bytes 数据,要么与 Python2 的处理方式略有不同。在大多数情况下,这要容易得多。

numerous ways to change the encoding 不是标准实践的一部分。但是有办法做到这一点。
最接近“好的”实践的是locale

locale.setlocale(locale.LC_ALL, 'sv_SE.UTF-8')

几年前我也有一个可怕的解决方案和方法,它看起来像这样(当时这对我来说是一个很好的选择):

tl;博士:

您的代码通常假定/使用 ASCII 作为编码器/解码器。
ö 不是 ASCII 的一部分,如果您知道如何获得 unicode 字符,您将始终看到\xf6。通常,如果您打印u'Ganztags ge\xf6ffnet',由于自动编码,它将显示为Ö,如果您需要验证输入是否与该字符串匹配,则必须比较它们u'ö' == u'ö',如果其他系统依赖此数据,请对其进行编码用他们理解的东西.encode('UTF-8')。但是用ö 替换\xf6 是一回事,只是ö 在ASCII 中不存在,你需要做u'ö' - 这将在最后产生相同的数据。

【讨论】:

  • 字符 ö 在 unicode 和 8 位 Latin1 编码中都有代码 \xf6,也称为 iso-8859-1。 Python 支持不同的 8 位编码,Latin1 常见于西欧语言,包括 Deutsch。
  • @SergeBallesta 这就是您现在所说的扩展 ASCII 表,对吧?因为默认的128 位表(我认为是)没有。 Python 支持大约 30 种左右的编码,但是默认不支持ö。 Latin1 != ASCII。
  • 我说的不是任何 扩展 ASCII,而是 Python 8 位字符串。 encodedecode 方法允许在 Python2 和 Python3 中分别将 8bits 字符串从 unicode 转换为 unicode。简单的程序员必须明确声明字符集。
  • @SergeBallesta 这正是我试图通过编码和解码来解决的问题。但是,如果我没记错的话,标准的 Python 字符串是 7 位的?
  • 而在 7 位 ASCII 中,没有 ö 这样的东西。假设 LSB,2^7=128。在这种情况下ö 的值是246。因为使用默认编码无法解析ö - 这就是我要在这里解决的问题。我不确定您是想对阅读本文的其他人有所启发,还是想以某种方式告诉我我错了。无论哪种方式,请说清楚。我假设是后者,如果是这样,你就错了(我认为)。 Python 2 在运行时是字节字符串文字,是的,在 Python3 中它们是 Unicode,基本上所有内容都是默认 UTF-8。
【解决方案2】:

当您使用德语时,您应该注意非 ascii 字符。 知道您的系统是否更喜欢 Latin1(Windows 控制台和一些 Unix)、UTF8(大多数 Linux 变体)或原生 unicode(Windows GUI)。

如果您可以将所有内容作为本机 unicode 处理,那么事情会更干净,您应该接受 u'ö'u'\xf6' 是相同字符的事实 - 后者完全独立于 python 源文件字符集。

如果您必须输出字节字符串并将它们存储在文件中,您应该将它们编码为 UTF8(可以处理任何 unicode 字符,但 127 以上的代码字符使用超过 1 个字节)或 Latin1(每个字符一个字节,但仅支持 256 以下的 unicode 码位)

在这种情况下,只需使用显式编码将您的 unicode 字符串转换为字节字符串:

print u'Ganztags ge\xf6ffnet'.encode('Latin1') # or .encode('utf8')

应该满足你的期望。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    相关资源
    最近更新 更多