Как исправить несоответствие чтения / открытия файла UnicodeEncodeError - PullRequest
0 голосов
/ 23 апреля 2019

Я недавно взял Python и унаследовал некоторый код Python 2.7, в котором я пытаюсь разрешить некоторые исключения. Для каждого аргумента командной строки (имя каталога) основной код вызывает импортированную функциональность для обработки там некоторых XML-файлов, затем соответствующий код инициализирует экземпляр класса, читая строки из файла «совпадений» и настраивая словарь для сопоставления ». сопоставлять строки с номерами строк в файле (это будет использоваться позже для обозначения совпадений строк, найденных в XML).

Сам файл совпадений никогда не меняется; это всегда один и тот же файл, загружаемый с диска. Это в формате UTF-8, около 12 тысяч строк, 100 из которых содержат символы не ASCII. В большинстве случаев эта загрузка происходит без помех. Однако иногда из этого кода выдается исключение: «UnicodeEncodeError: кодек« ascii »не может кодировать символ u '\ xf3' в позиции 12: порядковый номер не в диапазоне (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' и заметил, что это был <тип 'str'>, поэтому я попытался изменить строку 'open':

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

Это изменяет 'line' на "", а также изменяет вывод ошибок (для случаев с ошибками; в противном случае он работает так же, как и предыдущий код):

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? Или какое-то глобальное состояние в «открытом» коде? Или ...?

...