Python - Поиск проблем с Unicode / Ascii - PullRequest
2 голосов
/ 02 мая 2010

Я - csv.reader, чтобы получать информацию с очень длинного листа. Я работаю над этим набором данных, а затем использую пакет xlwt, чтобы получить работающий файл Excel.

Однако я получаю эту ошибку:

UnicodeDecodeError: кодек «ascii» не может декодировать байт 0x92 в позиции 34: порядковый номер не в диапазоне (128)

Мой вопрос ко всем вам, как я могу найти, где именно находится эта ошибка в моем наборе данных? Кроме того, есть ли какой-то код, который я могу написать, который просматривает мой набор данных и выясняет, где находятся проблемы (потому что некоторые наборы данных работают без вышеуказанной ошибки, а другие имеют проблемы)?

Ответы [ 4 ]

3 голосов
/ 02 мая 2010

На самом деле ответ довольно прост: как только вы прочитаете данные из файла, преобразуйте их в кодировку Unicode, используя кодировку вашего файла, и обработайте исключение UnicodeDecodeError:

try:
        # decode using utf-8 (use ascii if you want)
        unicode_data = str_data.decode("utf-8")
except UnicodeDecodeError, e:
        print "The error is there !"

это избавит вас от многих неприятностей; вам не придется беспокоиться о многобайтовой кодировке символов, а внешние библиотеки (включая xlwt) просто сделают правильную вещь, если им нужно это написать.

Python 3.0 сделает обязательным указание кодировки строки, так что это хорошая идея сделать это сейчас.

1 голос
/ 02 мая 2010

Модуль csv не поддерживает юникод и нулевые символы. Вы можете заменить их, выполнив что-то вроде этого (замените utf-8 на кодировку, в которую закодированы ваши данные CSV):

import codecs
import csv

class AsciiFile:
    def __init__(self, path):
        self.f = codecs.open(path, 'rb', 'utf-8')

    def close(self):
        self.f.close()

    def __iter__(self):
        for line in self.f:
            # 'replace' for unicode characters -> ?, 'ignore' to ignore them
            y = line.encode('ascii', 'replace')
            y = y.replace('\0', '?') # Can't handle null characters!
            yield y

f = AsciiFile(PATH)
r = csv.reader(f)
...
f.close()

Если вы хотите найти позиции символов, которые не могут быть обработаны модулем CSV, вы можете сделать, например:

import codecs

lineno = 0
f = codecs.open(PATH, 'rb', 'utf-8')
for line in f:
    for x, c in enumerate(line):
        if not c.encode('ascii', 'ignore') or c == '\0':
            print "Character ordinal %s line %s character %s is unicode or null!" % (ord(c), lineno, x)
    lineno += 1
f.close()

В качестве альтернативы, вы могли бы также использовать этот открыватель CSV, который я написал, который может обрабатывать символы Unicode:

import codecs

def OpenCSV(Path, Encoding, Delims, StartAtRow, Qualifier, Errors):
    infile = codecs.open(Path, "rb", Encoding, errors=Errors)
    for Line in infile:
        Line = Line.strip('\r\n')
        if (StartAtRow - 1) and StartAtRow > 0: StartAtRow -= 1
        elif Qualifier != '(None)':
            # Take a note of the chars 'before' just 
            # in case of excel-style """ quoting.
            cB41 = ''; cB42 = ''
            L = ['']
            qMode = False
            for c in Line: 
                if c==Qualifier and c==cB41==cB42 and qMode:
                    # Triple qualifiers, so allow it with one
                    L[-1] = L[-1][:-2]
                    L[-1] += c
                elif c==Qualifier: 
                    # A qualifier, so reverse qual mode
                    qMode = not qMode
                elif c in Delims and not qMode: 
                    # Not in qual mode and delim
                    L.append('')
                else: 
                    # Nothing to see here, move along
                    L[-1] += c
                cB42 = cB41
                cB41 = c
            yield L
        else:
            # There aren't any qualifiers.
            cB41 = ''; cB42 = ''
            L = ['']
            for c in Line: 
                cB42 = cB41; cB41 = c
                if c in Delims: 
                    # Delim
                    L.append('')
                else: 
                    # Nothing to see here, move along
                    L[-1] += c
            yield L

for listItem in openCSV(PATH, Encoding='utf-8', Delims=[','], StartAtRow=0, Qualifier='"', Errors='replace')
    ...
0 голосов
/ 02 мая 2010

ПОЖАЛУЙСТА, дайте полный возврат, который вы получили вместе с сообщением об ошибке. Когда мы знаем, где вы получаете сообщение об ошибке (читаете файл CSV, «выполняете работу с этим набором данных» или пишете файл XLS с использованием xlwt), мы можем дать сфокусированный ответ.

Вполне возможно, что ваши входные данные не все старые ASCII. Что его производит и в какой кодировке?

Чтобы найти, где проблемы (не обязательно ошибки), попробуйте небольшой скрипт, подобный этому (непроверенный):

import sys, glob
for pattern in sys.argv[1:]:
    for filepath in glob.glob(pattern):
        for linex, line in enumerate(open(filepath, 'r')):
            if any(c >= '\x80' for c in line):
                print "Non-ASCII in line %d of file %r" % (linex+1, filepath)
                print repr(line)

Было бы полезно, если бы вы показали некоторые примеры найденных вами «плохих» строк, чтобы мы могли судить о том, какой может быть кодировка.

Мне любопытно использовать "csv.reader для извлечения информации с очень длинного листа" - что это за "лист"? Вы имеете в виду, что вы сохраняете файл XLS как CSV, а затем читаете файл CSV? Если это так, вы можете использовать xlrd для чтения непосредственно из входного файла XLS, получая текст в кодировке Юникод, который вы можете передать прямо в xlwt, избегая проблем кодирования / декодирования.

Работали ли вы с учебником с сайта python-excel.org ?

0 голосов
/ 02 мая 2010

Вы можете обратиться к фрагментам кода в приведенном ниже вопросе, чтобы получить программу для чтения csv с поддержкой кодировки Unicode:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...