Как игнорировать пробельные символы Unicode, закодированные в UTF-8?

У меня есть CSV-файл со следующей информацией:

id  name    age     height  weight
1   x       12      11      124
2   y       13      23      432
3   z       14      43      1435

Он хранится в файле с именем Workbook2.csv. Я использую следующий код:

ipFile = csv.DictReader(open('Workbook2.csv', 'rU'))
dict = {} # Tring to update the rows to this dictionary.
for row in ipFile:
    print row

Я получаю следующий результат:

{'weight': '124', '\xef\xbb\xbfid': '1', 'height ': '11', 'age   ': '12', 'name ': 'x'}
{'weight': '432', '\xef\xbb\xbfid': '2', 'height ': '23', 'age   ': '13', 'name ': 'y'}
{'weight': '1435', '\xef\xbb\xbfid': '3', 'height ': '43', 'age   ': '14', 'name ': 'z'}

Я хотел бы знать, как я могу обновить этот вывод в словарь. Я также хотел бы знать, как я могу игнорировать символы Юникода, которые кодируются с использованием UTF-8, если есть фильтр, который я могу использовать для их устранения.

3 ответа

Ваши входные данные содержат последовательности спецификации UTF-8 в каждой строке. Что бы ни создавало этот файл, казалось, добавлял данные по одной строке за раз, используя utf-8-sig кодек или не-Python эквивалент. Спецификация (если используется вообще) должна быть первым символом в файле и не использоваться где-либо еще. Ваши данные повреждены, если вы можете исправить это у источника, сделайте это.

Тем не менее, есть способ исправить это, как вы читаете. "Файл", который читается csv Модуль может быть чем угодно, что выдает строки во время итерации. Сначала используйте генератор для фильтрации строк файла:

from codecs import BOM_UTF8

def bom_filter(lines):
    for line in lines:
        if line.startswith(BOM_UTF8):
            line = line[len(BOM_UTF8):]
        yield line

затем передайте файл через фильтр, прежде чем передать его DictReader() объект:

with open('Workbook2.csv', 'rU') as inputfile:
    ipFile = csv.DictReader(bom_filter(inputfile))

Демо-версия:

>>> from io import BytesIO
>>> import csv
>>> from codecs import BOM_UTF8
>>> def bom_filter(lines):
...     for line in lines:
...         if line.startswith(BOM_UTF8):
...             line = line[len(BOM_UTF8):]
...         yield line
...
>>> demofile = BytesIO('''\
... \xef\xbb\xbfid,name,age,height,weight
... \xef\xbb\xbf1,x,12,11,124
... \xef\xbb\xbf2,y,13,23,432
... \xef\xbb\xbf3,z,14,43,1435
... ''')
>>> ipFile = csv.DictReader(bom_filter(demofile))
>>> for row in ipFile:
...     print row
...
{'age': '12', 'height': '11', 'id': '1', 'weight': '124', 'name': 'x'}
{'age': '13', 'height': '23', 'id': '2', 'weight': '432', 'name': 'y'}
{'age': '14', 'height': '43', 'id': '3', 'weight': '1435', 'name': 'z'}

В Python 3 csv Модуль принимает строковый ввод в Юникоде (в отличие от байтовых строк, поэтому теперь вам нужно искать декодированный результат - код пробела нулевой ширины U+FEFF. Чтобы код работал на любой версии Python, вам нужно поменять вы проверяете в начале строки:

import sys
to_filter = u'\ufeff'
if sys.version_info < (3,):
    to_filter = to_filter.encode('utf8')

def bom_filter(lines):
    for line in lines:
        if line.startswith(to_filter):
            line = line[len(to_filter):]
        yield line

Существует скипинитальное пространство kwarg, но из кода C я убедился, что он ищет только ' '.

Две возможности:

  1. Подкласс DictReader для добавления кода для удаления пробелов
  2. Массируйте строки из вашего файла, прежде чем передавать их в DictReader.

Примером (2) будет:

import io
with io.open('Workbook2.csv', 'r', encoding='utf8') as infile:
    ipFile = csv.DictReader((x.replace(u"\uFEFF", u" ") for x in infile))
....

Я думаю, что вывод явно неверно истолкован.

DictReader берет имена полей из первой строки, а первый столбец (тот, что после невидимой спецификации) - это просто "id". Вот почему поле id теперь имеет спецификацию, добавленную в каждую запись.

В Python 2.7 и 3.6 мне пришлось использовать диалект csv.excel_tab включить интерпретацию вкладок как разделителей.

Ваш входной файл data / csv абсолютно нормален, так как в начале есть только спецификация (где она должна быть). Вам просто нужно раздеть спецификацию перед чтением.

Например, вот так:

from codecs import BOM_UTF8
csv_file = open('test2.csv', 'rU')
csv_file.seek(len(BOM_UTF8))
ipFile = csv.DictReader(csv_file, dialect=csv.excel_tab)
Другие вопросы по тегам