在 Python 中使用 unidecode
库可以将 Unicode 文本转换为 ASCII。这对于需要处理非英文字符的文本并且希望保持可读性时非常有用。以下是如何在 Python 中使用 unidecode
库的示例和步骤:
1、问题背景
我正在尝试从文本文件中删除所有非 ASCII 字符。我找到一个程序包应该可以做到这一点,https://pypi.python.org/pypi/Unidecode。它应该接受一个字符串并将所有非 ASCII 字符转换为最接近的可用 ASCII 字符。我在 perl 中很容易地使用了这个模块,只需调用 while (<input>) { $_ = unidecode($_); }
,这个模块是对 perl 模块的直接移植,文档表明它应该以相同的方式工作。 我确信这是一个简单的问题,我只是对字符和文件编码了解不够,不知道问题出在哪里。我的原始文件编码为 UTF-8(从 UCS-2LE 转换而来)。问题可能更多地与我缺乏编码知识和错误处理字符串有关,而不是模块,但希望有人可以解释一下原因。到目前为止,我已经尝试了我所知道的一切,没有随机插入代码并搜索我遇到的错误。
以下是我的 Python 代码:
from unidecode import unidecodedef toascii():origfile = open(r'C:\log.convert', 'rb')convertfile = open(r'C:\log.toascii', 'wb')for line in origfile:line = unidecode(line)convertfile.write(line)origfile.close()convertfile.close()toascii();
如果我不在字节模式下打开原始文件(origfile = open(‘file.txt’,‘r’)),那么我会收到错误 UnicodeDecodeError: ‘charmap’ codec can’t decode byte 0x90 in position 1563: character maps to 来自 for line in origfile: line.
。 如果我确实在字节模式 ‘rb’ 中打开它,那么我收到 TypeError: ord() expected string length 1, but int found 来自 line = unidecode(line)
。 如果我将 line 声明为字符串 line = unidecode(str(line)) 那么它会写入文件,但…不正确。\r\n'b'\xef\xbb\xbf[ 2013.10.05 16:18:01 ] User_Name > .\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\
,它正在写出 \n、\r 等和 unicode 字符而不是将它们转换为任何东西。 如果我像上面一样将这行转换为字符串,并在字节模式 ‘wb’ 中打开转换文件,那么会给出错误 TypeError: ‘str’ does not support the buffer interface。 如果我不声明它为字符串 ‘wb’ 并 unidecode(line) 在字节模式下打开它,那么我再次收到 TypeError: ord() expected string length 1, but int found 错误。
2、解决方案
unidecode 模块接受 unicode 字符串值并返回 Python 3 中的 unicode 字符串。你给它的是二进制数据。解码成 unicode 或在文本模式下打开输入文本文件,并在写入文件之前将结果编码成 ASCII,或在文本模式下打开输出文本文件。 引用模块文档:
该模块导出一个函数,该函数采用 Unicode 对象(Python 2.x)或字符串(Python 3.x)并返回一个字符串(可以在 Python 3.x 中编码为 ASCII 字节)
重点是我的。
以下应有效:
def toascii():with open(r'C:\log.convert', 'r', encoding='utf8') as origfile, open(r'C:\log.toascii', 'w', encoding='ascii') as convertfile:for line in origfile:line = unidecode(line)convertfile.write(line)
这以文本模式打开输入文件(使用 UTF8 编码,根据示例行判断,这是正确的)并以文本模式写入(编码为 ASCII)。 你确实需要显式指定要打开的文件的编码;如果你省略了编码,那么使用当前系统区域设置(locale.getpreferredencoding(False) 调用结果),如果你的代码需要是可移植的,那么这通常不是正确的编解码器。
其实说白了通过使用 unidecode
,我们可以有效地处理包含多种语言字符的文本,使其更易于处理和分析,同时保持文本的可读性。