Сравнение строк в Python - проблемы со специальными / юникод-символами - PullRequest
4 голосов
/ 08 марта 2011

Я пишу скрипт на Python для обработки некоторых музыкальных данных.Предполагается объединить две отдельные базы данных, сравнив их записи и сопоставив их.Это почти работает, но не удается при сравнении строк, содержащих специальные символы (то есть буквы с акцентом).Я почти уверен, что это проблема кодировки ASCII и Unicode, так как я получаю сообщение об ошибке:

"При сопоставлении Unicode равно не удалось преобразовать оба аргумента в Unicode - интерпретировать их как неравные"

Я понимаю, что мог бы использовать регулярные выражения для удаления оскорбительных символов, но я обрабатываю много данных и слишком много полагаюсь на регулярные выражения, что делает мою программу невероятно медленной.Есть ли способ, чтобы Python правильно сравнивал эти строки?Что здесь происходит - есть ли способ узнать, хранит ли он мои строки как ASCII или Unicode?

РЕДАКТИРОВАТЬ 1: Я использую Python v2.6.6.После проверки типов я обнаружил, что одна база данных выдает мне строки Unicode, а другая - ASCII.Так что это, вероятно, проблемы.Я пытаюсь преобразовать строки ASCII из второй базы данных в Unicode со строкой вроде

line = unicode(f.readline().decode(latin_1).encode(utf_8))

, но это выдает ошибку вроде:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 41: ordinal not in range(128)

Я не уверен, почемукодек 'ascii' жалуется, так как я пытаюсь декодировать из ASCII.Кто-нибудь может помочь?

Ответы [ 4 ]

5 голосов
/ 08 марта 2011

Юникод против байтов

Сначала немного терминологии. Существует два типа строк, закодированных и декодированных:

  • закодированные. Это то, что хранится на диске. Для Python это набор из 0 и 1, который вы можете рассматривать как ASCII, но это может быть что угодно - двоичные данные, изображение JPEG, что угодно. В Python 2.x это называется «строковой» переменной. В Python 3.x его более точно называют переменной «байтов».
  • Раскодированный. Это строка реальных символов. Они могут быть закодированы в 8-битные строки ASCII или в 32-битные китайские символы. Но пока не пришло время конвертировать в закодированную переменную , это всего лишь строка символов Unicode.

Что это значит для вас

Так вот в чем дело. Вы сказали, что получаете одну переменную ASCII и одну переменную Unicode. На самом деле это не так.

  • У вас есть одна переменная, представляющая собой строку байтов - единиц и нулей, предположительно в наборах по 8. Это переменная, которую вы ошибочно приняли за ASCII.
  • У вас есть другая переменная, которая представляет собой данные Unicode - цифры, буквы и символы.

Прежде чем сравнивать строку байтов со строкой символов Юникода, необходимо сделать некоторые предположения. В вашем случае Python (и вы) предположили, что строка байтов была закодирована в ASCII. Это работало нормально, пока вы не наткнулись на персонажа, который не был ASCII - персонаж с акцентом.

Так что вам нужно выяснить, как кодируется эта строка байтов. Это может быть латынь1. Если это так, вы хотите сделать это:

if unicode_variable == string_variable.decode('latin1')

Latin1 - это в основном ASCII плюс некоторые расширенные символы, такие как Ç и В.

Если ваши данные на латыни1, это все, что вам нужно сделать. Но если ваша строка байтов кодируется во что-то еще, вам нужно выяснить, что это за кодировка, и передать ее в decode ().

Суть в том, что нет простого ответа, если вы не знаете (или не делаете некоторых предположений) о кодировании ваших входных данных.

Что бы я сделал

Попробуйте запустить var.decode ('latin1') для вашей строки байтов. Это даст вам переменную Unicode. Если это работает, и данные выглядят правильно (т. Е. Символы с символами ударения выглядят так, как будто они принадлежат), используйте их.

Да, и если latin1 не анализирует или выглядит неправильно, попробуйте utf8 - другую распространенную кодировку.

0 голосов
/ 08 марта 2011

Преобразование обоих в юникод должно помочь:

if unicode(str1) == unicode(str2):
    print "same" 
0 голосов
/ 08 марта 2011

Чтобы узнать, храните ли вы (не это) ваши строки как str объекты или unicode объекты, print type(your_string).

Вы можете использовать print repr(your_string), чтобы однозначно показать себе (и нам), что находится в вашей строке.

Кстати, какую именно версию Python вы используете, на какой ОС? Если Python 3.x, используйте ascii() вместо repr().

0 голосов
/ 08 марта 2011

Может потребоваться предварительная обработка баз данных и преобразование всего в UTF-8.Я предполагаю, что у вас есть символы латинского алфавита 1 в некоторых записях.Что касается вашего вопроса, единственный способ узнать наверняка - это посмотреть.Сделайте так, чтобы ваш скрипт выплевывал те, которые не сравниваются, и ищите коды символов.Или просто попробуйте string.decode('latin1').encode('utf8') и посмотрите, что получится.

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