如何将字符串从CP-1251转换为UTF-8?

时间:2011-09-26 12:51:22

标签: python utf-8 wxpython cp1251

我正在使用mutagen将ID3标签数据从CP-1251 / CP-1252转换为UTF-8。在Linux中没有问题。但是在Windows上,在wx.TextCtrl上调用SetValue()会产生错误:

  

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

我从mutagen提取的原始字符串(假设为CP-1251编码)是:

u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'

我尝试将其转换为UTF-8:

dd = d.decode('utf-8')

...甚至将默认编码从ASCII更改为UTF-8:

sys.setdefaultencoding('utf-8')

......但我得到同样的错误。

6 个答案:

答案 0 :(得分:25)

如果您确定输入中有cp1251,则可以

d.decode('cp1251').encode('utf8')

答案 1 :(得分:5)

您的字符串d是一个Unicode字符串,不是一个UTF-8编码的字符串!所以你不能decode()它,你必须encode()它到UTF-8或你需要的任何编码。

>>> d = u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> d
u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> print d
Áåëàÿ ÿáëûíÿ ãðîìó
>>> a.encode("utf-8")
'\xc3\x81\xc3\xa5\xc3\xab\xc3\xa0\xc3\xbf \xc3\xbf\xc3\xa1\xc3\xab\xc3\xbb\xc3\xad\xc3\xbf \xc3\xa3\xc3\xb0\xc3\xae\xc3\xac\xc3\xb3'

(例如,当您需要将其保存为UTF-8编码文件时,这是您在所有处理结束时所做的事情。)

如果你的输入采用不同的编码,那就是另一种方式:

>>> d = "Schoßhündchen"                 # native encoding: cp850
>>> d = "Schoßhündchen".decode("cp850") # decode from Windows codepage
>>> d                                   # into a Unicode string (now work with this!)
u'Scho\xdfh\xfcndchen'
>>> print d                             # it displays correctly if your shell knows the glyphs
Schoßhündchen
>>> d.encode("utf-8")                   # before output, convert to UTF-8
'Scho\xc3\x9fh\xc3\xbcndchen'

答案 2 :(得分:4)

如果d是正确的Unicode字符串,则d.encode('utf-8')会产生编码的UTF-8字节字符串。不要通过打印来测试它,但是,由于代码页的恶作剧,它可能无法正常显示。

答案 3 :(得分:0)

我在此回复中提供了有关编码/解码文本的一些相关信息:https://stackoverflow.com/a/34662963/2957811

要在此添加,重要的是要考虑两种可能状态之一的文本:'encoded'和'decoding'

'decode'表示它是由您的解释器/库在内部表示,可用于字符操作(例如搜索,大小写转换,子串切片,字符计数......)或显示(查找代码点)以字体和绘制字形),但不能传入或传出正在运行的进程。

'encoded'表示它是一个可以像任何其他数据一样传递的字节流,但对操作或显示没有用。

如果您之前使用过序列化对象,请将“已解码”视为内存中的有用对象,并将“已编码”视为序列化版本。

'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'是您的编码(或序列化)版本,可能是用cp1251编码的。这种编码需要正确,因为这是用于序列化字符的“语言”,需要在内存中重新创建字符。

需要从它的当前编码(cp1251)解码为python unicode字符,然后将其重新编码为utf8字节流。建议d.decode('cp1251').encode('utf8')的回答者有这个权利,我只是希望帮助解释为什么这应该有效。

答案 4 :(得分:0)

我失去了一半的时间来找到正确的答案。所以如果你从外部源windows-1251编码得到一些unicode字符串(在我的情况下来自网站),你会在Linux控制台中看到这样的东西:

u'\ u043a \ u043e \ u043c \ u043d \ u0444 \ u0442 \ u043d \ u0430 \ u044f \ u043a \ u0432 \ u0430 \ u0440 \ u0442 \ u0438 \ u0440 \ u0430 .....'

这不是您的数据的unicode显示。所以,Tim Pietzcker是对的。你应首先编码()然后解码()然后再次编码以纠正编码。

所以在我的情况下,这个奇怪的行保存在“text”变量中,并且行:

print text.encode("cp1251").decode('cp1251').encode('utf8')   

给了我:

“Своя2-хкомнатнаяквартирасотличнымремонтом....”

是的,它也让我发疯。但它有效!

P.S。保存到文件你应该以同样的方式。

some_file.write(text.encode("cp1251").decode('cp1251').encode('utf8'))

答案 5 :(得分:0)

我宁愿在АлександрСтепаненк®答案中添加评论,但我的声誉还不允许。我有类似的问题,将MP3标签从CP-1251转换为UTF-8,编码/解码/编码解决方案对我有用。除了我必须用“latin-1”替换第一个编码,它实际上将Unicode字符串转换为字节序列而没有实际编码:

print text.encode("latin-1").decode('cp1251').encode('utf8')

并且为了使用例如mutagen进行保存,它不需要编码:

audio["title"] = title.encode("latin-1").decode('cp1251')