Читайте CSV с вопросительными знаками в штучной упаковке - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть файл CSV (на французском языке), в котором строки текста выглядят следующим образом:

"Vend, 21 sept, 2018","43326370894332743328177832888443325333815370","NX","651-2141652-1309NON666-3778692-2229581-300-6525622-9439NON581-998-8765827-3937STOPNON653-2541Toronto","RoyRoyHoudeOuelletFecteauRenaudBergeronLeclercBadeaux","Louise-AndréeAndréRichardAlexandraPaulineElianeCharles-EugèneGuyJacqueline","Vendredi, 21 septembre, 2018","","","3","37089","","100","","204-7584","MIller ","claudia","8:30 pt ne s'est pas présenté (gastro) veut un autre rdv","370892192018","581-309-1309660-3064fille254-6560cel650-4556"

Я прочитал его в Python, используя следующий код:

import csv
filepath = 'RDV.csv'
try:
    with open(filepath, 'rU') as file:
        try:
            reader = csv.reader(x.replace('\0', '') for x in file)
            for row in reader:
                try:
                    print(row)
                except Exception as ee:
                    print ee
        except Exception as eee:
            print eee
except Exception as e:
    print e

Это читается как:

['Vend, 21 sept, 2018', '43326\x1d\x1d37089\x1d\x1d43327\x1d43328\x1d17783\x1d28884\x1d\x1d\x1d43325\x1d33381\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d5370', '\x1d\x1d\x1d\x1dNX', '651-2141\x1d\x1d652-1309\x1dNON\x1d666-3778\x1d692-2229\x1d581-300-6525\x1d622-9439\x1d\x1dNON\x1d581-998-8765\x1d827-3937\x1dSTOP\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1dNON\x1d653-2541\x1d\x1d\x1dToronto', 'Roy\x1d\x1dRoy\x1d\x1dHoude\x1dOuellet\x1dFecteau\x1dRenaud\x1d\x1d\x1dBergeron\x1dLeclerc\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1dBadeaux', 'Louise-Andr\x8ee\x1d\x1dAndr\x8e\x1d\x1dRichard\x1dAlexandra\x1dPauline\x1dEliane\x1d\x1d\x1dCharles-Eug\x8fne\x1dGuy\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1dJacqueline', 'Vendredi, 21 septembre, 2018', '', '', '3', '37089', '', '100', '', '204-7584', 'MIller ', 'claudia', "8:30 pt ne s'est pas pr\x8esent\x8e (gastro) veut un autre rdv\x0b", '370892192018', '\x1d\x1d581-309-1309\x1d\x1d\x1d\x1d660-3064fille\x1d254-6560cel\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d650-4556']
  1. Как его можно читать как обычный текст вместо этих закодированных символов?
  2. Как искать символ � в значениях - для пример:

    Луиза-АндреАндр�РичардАлександраПолинElianeCharles-Eug�neGuyJacqueline

Редактировать:

Я пробовал код из ответа snakecharmerb, но я получаю следующую ошибку :

Traceback (most recent call last):
  File "<input>", line 20, in <module>
  File "<input>", line 9, in unicode_csv_reader
  File "<input>", line 15, in utf_8_encoder
  File "/Users/simran/Documents/abc/venv/lib/python2.7/codecs.py", line 701, in next
    return self.reader.next()
  File "/Users/simran/Documents/abc/venv/lib/python2.7/codecs.py", line 632, in next
    line = self.readline()
  File "/Users/simran/Documents/abc/venv/lib/python2.7/codecs.py", line 547, in readline
    data = self.read(readsize, firstline=True)
  File "/Users/simran/Documents/abc/venv/lib/python2.7/codecs.py", line 494, in read
    newchars, decodedbytes = self.decode(data, self.errors)
  File "/Users/simran/Documents/abc/venv/lib/python2.7/encodings/utf_16.py", line 112, in decode
    raise UnicodeError,"UTF-16 stream does not start with BOM"
UnicodeError: UTF-16 stream does not start with BOM

1 Ответ

1 голос
/ 25 апреля 2020

Файл, вероятно, закодирован как UTF-16.

>>> s = '"Vend, 21 sept, 2018","43326370894332743328177832888443325333815370","NX","651-2141652-1309NON666-3778692-2229581-300-6525622-9439NON581-998-8765827-3937STOPNON653-2541Toronto","RoyRoyHoudeOuelletFecteauRenaudBergeronLeclercBadeaux","Louise-AndréeAndréRichardAlexandraPaulineElianeCharles-EugèneGuyJacqueline","Vendredi, 21 septembre, 2018","","","3","37089","","100","","204-7584","MIller ","claudia","8:30 pt ne s\'est pas présenté (gastro) veut un autre rdv","370892192018","581-309-1309660-3064fille254-6560cel650-4556"'
>>> buf = io.BytesIO(s.decode('utf-8').encode('utf-16'))
>>> next(csv.reader(buf))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
 _csv.Error: line contains NULL byte

Python2 Модуль CSV не обрабатывает UTF-16, как и пакет unicodecsv . Однако мы можем изменить unicode_csv_reader из примеров в документах :

import codecs
import csv 


def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                            dialect=dialect, **kwargs)
    for row in csv_reader:
        # decode UTF-8 back to Unicode, cell by cell:
        yield [unicode(cell, 'utf-8') for cell in row]


def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')


with codecs.open('french2.csv', 'rU', encoding='utf-16') as f:
    for row in unicode_csv_reader(f):
        for cell in row:
            print cell

Код производит этот вывод (одна ячейка печатается на строку только для отображения акцентированных символов):

Vend, 21 sept, 2018
43326370894332743328177832888443325333815370
NX
651-2141652-1309NON666-3778692-2229581-300-6525622-9439NON581-998-8765827-3937STOPNON653-2541Toronto
RoyRoyHoudeOuelletFecteauRenaudBergeronLeclercBadeaux
Louise-AndréeAndréRichardAlexandraPaulineElianeCharles-EugèneGuyJacqueline
Vendredi, 21 septembre, 2018


3
37089

100

204-7584
MIller 
claudia
8:30 pt ne s'est pas présenté (gastro) veut un autre rdv
370892192018
581-309-1309660-3064fille254-6560cel650-4556

Ничего из этого не потребуется в Python3, вы можете просто сделать:

with open(myfile, 'r', newline='', encoding='utf-16') as f:
    reader = csv.reader(f)
    for row in reader:
        ...

Обзор

Идентификация кодировки

Угадывание неизвестной кодировки является проблемой без общее решение. В этом случае мы знаем, что закодированный текст содержит нулевые байты и что удаление нулевых байтов оставляет шестнадцатеричный escape, где мы ожидаем увидеть акцентированный европейский символ, но европейские символы без акцента остаются неизменными. Этого достаточно, чтобы предположить, что файл может быть закодирован как UTF-16; Для символов в диапазоне ASCII кодировка UTF-16 эффективно добавляет или добавляет нулевой байт к символу ASCII.

>>> u = u'André'
>>> s = u.encode('utf-16-le')
>>> s
'A\x00n\x00d\x00r\x00\xe9\x00'

Кодировка UTF-16 может быть с прямым или прямым порядком байтов; порядковый номер определяет, предшествует или следует ли нулевой байт символ ASCII. Байты могут включать в себя метку порядка байтов (BOM), которая указывает порядковый номер; в этом случае кодировка может быть указана как UTF-16 и Python выберет правильную кодировку. В отсутствие спецификации, utf-16-le или utf-16-be должны быть указаны явно.

Символ (('\ uffd') является символом замены Юникода и используется для отображения символов которые не могут быть отображены в выбранной кодировке (при условии, что аргумент errors для str.encode имеет значение «заменить», явно или неявно)

>>> print s
Andr�
Чтение модуля csv csv

Python 2 делает не справляется с кодировками не-ASCII. Чтобы обойти его ограничения, код выше

  • декодирует содержимое файла с utf-16 в unicode
  • перекодирует как utf-8 (чтобы избежать нулевых байтов)
  • декодирует содержимое каждой ячейки из utf-8 в Unicode

После того, как содержимое было возвращено в программу как Unicode, оно может быть обработано без проблем, пока не будет закодировано для записи в файл или печать.

В Python 3 обработка текста, не относящегося к ASCII, намного проще: этот код сделает всю работу:

with open('french.csv', newline='', encoding='utf-16') as f:
    reader = csv.reader(f)
    for row in f:
       print(row)
...