Как игнорировать пробельные символы 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 я убедился, что он ищет только ' '.
Две возможности:
- Подкласс DictReader для добавления кода для удаления пробелов
- Массируйте строки из вашего файла, прежде чем передавать их в 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)