2017-01-23 5 views
1

Я читаю .csv, который закодирован в UTF-8. Я хочу создать индекс и переписать csv. Индекс создается как постоянное число и первая буква слова. Python 2.7.10, Ubuntu ServerНеисправность при кодировании/декодировании utf-8

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
counter = 0 
tempDict = {} 
with open(modifiedFile, "wb") as newFile: 
    with open(originalFile, "r") as file: 
     for row in file: 
      myList = row.split(",") 
      toId = str(myList[0]) 

      if toId not in tempDict: 
       tempDict[toId] = counter 
       myId = str(toId[0]) + str(counter) 
       myList.append(myId) 
       counter += 1 
      else: 
       myId = str(toId[0]) + str(tempDict[toId]) 
       myList.append(myId) 

      # and then I write everything into the csv 
      for i, j in enumerate(myList): 
       if i < 6: 
        newFile.write(str(j).strip()) 
        newFile.write(",") 

       else: 
        newFile.write(str(j).strip()) 
        newFile.write("\n") 

Проблема заключается в следующем. Когда слово начинается с буквы фантазии, такие как

  • Č
  • É
  • Ā
  • ...

Ид создать начинается с ?, но не с буквой слова. Странная часть состоит в том, что с созданием csv я создаю слова с причудливыми буквами. Нет ? или других символов, которые указывают на неправильную кодировку.

Почему?

+1

Какую версию python вы используете? –

+0

И если вы работаете в Windows, возможно, он использует кодировку локали. –

+0

@TimMartin 2.7.10, работая на 'Ubuntu Server' – Stophface

ответ

0

В строке python 2.x по умолчанию не-unicode - str() возвращает строку, отличную от юникода. Вместо этого используйте unicode().

Кроме того, вы должны открыть файл, используя utf-8, вместо codecs.open(), а не встроенный open().

+0

Хм, но почему другие слова закодированы правильно? Будет ли обновление до python 3.x решить эту проблему? – Stophface

+0

@Stophface * почему другие слова закодированы правильно * В 'toId [0]', когда 'toId' запускается с многобайтовым символом, вы фактически берете только первый байт, после чего он перестает быть допустимым символом. Вся оставшаяся часть обработки просто копирует входные данные без изменений (разделение запятыми не создает никаких проблем). – Leon

+0

@Stophface * Будет ли обновление до python 3.x решить эту проблему * Да – Leon

3

В любом случае, вы не должны изучать Python 2, если не существует specific устаревшего расширения C, которое вам нужно.

Python 3 вносит существенные изменения в обработку unicode/bytes, которая удаляет (наиболее) неявное поведение и делает ошибки видимыми. По-прежнему хорошей практикой является использование open('filename', encoding='utf-8'), поскольку стандартная кодировка зависит от среды и платформы.

Действительно, запуск вашей программы в Python 3 должен исправить ее без каких-либо изменений. Но вот где ваша ошибка заключается:

 toId = str(myList[0]) 

Это является не-оп, так как myList[0] уже str.

  myId = str(toId[0]) + str(counter) 

Это ошибка: toId является (строка байт) а str, содержащий данные UTF-8. Вы никогда, никогда не хотите что-либо делать с данными UTF-8, за исключением того, что обрабатываете его по одному символу за раз.

with open(originalFile, "r") as file: 

Это ошибка стиля, поскольку это маскирует встроенная функция file.

Есть два изменения, чтобы сделать этот пробег под Python 2.

  1. Изменения open(filename, mode) в io.open(filename, mode, encoding='utf-8').
  2. Стоп вызова str() на строки, так что на самом деле пытается кодировать их (в ASCII!).

Но вы действительно должны перейти на Python 3.

Есть несколько штук новых 2.6 и 2.7, которые предназначены для преодоления разрыва до 3, и один из них является модуль io, который ведет себя во всех приятных новых способах: Unicode-файлы и универсальные символы новой строки.

~$ python2.7 -c 'import io,sys;print(list(io.open(sys.argv[1],encoding="u8")))' <(printf $'\xc3\x84\r\n\xc3\xb9\r\n') 
[u'\xc4\n', u'\xf9\n'] 
~$ python3 -c 'import sys;print(list(open(sys.argv[1],encoding="u8")))' <(printf $'\xc3\x84\r\n\xc3\xb9\r\n') 
['Ä\n', 'ù\n'] 

Это может быть полезно, чтобы написать программное обеспечение как для 2 и 3. Опять же, кодирование аргумент является необязательным, но на всех платформах кодировкой по умолчанию является экологически зависимым, так что это хорошо, чтобы быть конкретным.

+1

В Python 2, вы должны использовать 'io.open()', который более точно соответствует PY3 'открытой()' и дает соответствующие универсальной поддержки линии –

+1

Спасибо, мой 2to3 немного ржавый :) –