首页 > 解决方案 > 如何修复不一致的 UnicodeEncodeError 读取/打开文件

问题描述

我最近学习了 Python,并继承了一些 Python 2.7 代码,我试图在其中解决一些异常。对于每个命令行参数(目录名),主代码调用导入的功能来处理那里的一些 XML 文件,然后有问题的代码通过从“匹配”文件中读取行并设置字典以映射“ match" 字符串到文件中的行号(稍后将用于标记在 XML 中找到的字符串匹配项)。

匹配文件本身永远不会改变;它总是从磁盘加载相同的文件。它采用 UTF-8 格式,大约 12000 行,其中 100 行包含非 ASCII 字符。大多数情况下,这种加载会顺利进行。但是,有时,此代码会引发异常:“UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 12: ordinal not in range(128)”。字符代码和位置也有很大差异。我已经验证了正在读取的文件名和文件内容永远不会改变;只是偶尔,Python 决定为它通常可以读取的相同数据抛出异常!

我注意到这些异常似乎总是在导入的模块报告处理内部列表的错误之后发生,但这如何使不同的模块突然对以前可接受的数据抛出异常是一个谜。

这是我最初看到的错误:

ProcessXML - entry 52 bad list string, skipping...
class StrMatcher.__init__ called
Traceback (most recent call last):
  File "/home/tests/my_main.py", line 19, in my_main
    obj = StrMatcher("/home/tests/match_strings.txt")
  File "/home/tests/my_common.py", line 20, in __init__
    for line in f:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 12: ordinal not in range(128)

从这段代码:

class StrMatcher:
    def __init__(self, matches_file):
        print("StrMatcher.__init__ called")
        self.line_numbers = {}
        i = 1
        with open(matches_file, 'r') as f:
            for line in f:
                self.line_numbers[line.strip()] = i
                i += 1

(与其他关于 Python Unicode 错误的问题不同,尽管总是处理完全相同的数据,但此错误的发生不一致。)

我打印出'i',并看到错误发生在从文件中读取最后一行之后(所以大概它正在尝试处理 EOF)。我打印出 'line' 的类型,并注意到它是“<type 'str'>”,所以我尝试更改 'open' 行:

        with io.open(matches_file, mode='r', encoding="utf-8") as f:

这会将 'line' 更改为 "<type 'unicode'>",并且还会更改错误输出(对于那些有错误的情况;否则,它与前面的代码一样有效):

ProcessXML - entry 52 bad list string, skipping...
class StrMatcher.__init__ called
Traceback (most recent call last):
  File "/home/tests/my_main.py", line 19, in my_main
    obj = StrMatcher("/home/tests/match_strings.txt")
  File "/home/tests/my_common.py", line 19, in __init__
    with io.open(matches_file, mode='r', encoding="utf-8") as f:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 12: ordinal not in range(128)

表现出“ProcessXML”错误的不同输入目录(和/或可能相同目录的不同运行,不确定)使异常字符/范围跳转,例如

UnicodeEncodeError: 'ascii' codec can't encode character u'\xfa' in position 43: ordinal not in range(128)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 91: ordinal not in range(128)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u200b' in position 52: ordinal not in range(128)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 48-50: ordinal not in range(128)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 37: ordinal not in range(128)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 32: ordinal not in range(128)

到底是怎么回事?'ascii' 编解码器试图编码什么以及为什么要编码,尤其是在以“utf-8”模式打开文件时?

我假设在错误情况下导入的模块无意中更改了某些状态,但令我惊讶的是,当可以打开和读取完全相同的文件/数据时,任何东西都可以使读取行或在另一个模块中打开文件引发 UnicodeEncodeError在其他情况下使用相同的代码!它是 Python 2.7 的错误吗?还是“开放”代码中的一些全局状态?或者...?

标签: pythonpython-2.7python-unicode

解决方案


推荐阅读