Я начал пытаться хранить строки в SQLite с помощью питона, и получил сообщение:SQLite, Python, Юникод и не-UTF данные
sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.
Хорошо, я переключился на строки Unicode. Затем я начал получать сообщение:
sqlite3.OperationalError: Could not decode to UTF-8 column 'tag_artist' with text 'Sigur Rós'
при попытке извлечь данные из базы данных. Необходимы дополнительные исследования, и я начал кодирования его в utf8, но начинается тогда «Sigur Ros» похожий «Sigur Rós»
примечание: Моя консоль была настроена на показ в «latin_1» как @John Мачин указал.
Что дает? После прочтения this, описывая точно такую же ситуацию, в которой я оказался, кажется, что совет состоит в том, чтобы игнорировать другой совет и использовать 8-битные байты в конце концов.
Я не знал много о unicode и utf, прежде чем начал этот процесс. За последние пару часов я узнал немало, но я все еще не знаю, есть ли способ правильно преобразовать '-' из латинского-1 в utf-8 и не калечить его. Если этого не произойдет, почему SQLite настоятельно рекомендует переключить мое приложение на строки unicode?
Я буду обновлять этот вопрос с кратким и некоторые примеры кода из всего, что я узнал за последние 24 часов, так что кто-то в моей обуви может иметь легкий (ER) руководство. Если информация, которую я публикую, неверна или вводит в заблуждение, пожалуйста, скажите мне, и я обновлю, или один из вас, старшие ребята, может обновить.
Резюме ответов
Позвольте мне первой государственной цели, как я понимаю. Целью обработки различных кодировок, если вы пытаетесь преобразовать их между собой, является понимание того, что такое исходная кодировка, а затем преобразовать ее в unicode с использованием этой исходной кодировки, а затем преобразовать ее в нужную кодировку. Unicode является базой, а кодировки - отображением подмножеств этой базы. utf_8 имеет место для каждого символа в юникоде, но поскольку они не находятся на том же месте, что, например, latin_1, строка, закодированная в utf_8 и отправленная в консоль latin_1, не будет выглядеть так, как вы ожидаете. В питона процесс получения в юникод и в другой кодировке выглядит следующим образом:
str.decode('source_encoding').encode('desired_encoding')
или если Обл уже в юникодом
str.encode('desired_encoding')
Для SQLite я на самом деле не хочу, чтобы кодировать его снова, Я хотел расшифровать его и оставить в формате Unicode. Вот четыре вещи, которые вам, возможно, нужно знать, когда вы пытаетесь работать с юникодом и кодировками в python.
- Кодирование строки, с которой вы хотите работать, и кодировку, которую вы хотите получить.
- Системное кодирование.
- Консольное кодирование.
- Кодирование исходного файла
Elaboration:
(1) Когда вы читаете строку из источника, он должен иметь некоторую кодировку, как latin_1 или UTF_8. В моем случае я получаю строки из имен файлов, поэтому, к сожалению, я могу получить какую-либо кодировку. Windows XP использует UCS-2 (система Unicode) как свой собственный тип строки, который мне кажется изменчивым. К счастью для меня, символы в большинстве имен файлов не состоят из более чем одного типа кодировки источника, и я думаю, что все мои были либо полностью latin_1, полностью utf_8, либо просто ascii (который является подмножеством обоих те). Поэтому я просто прочитал их и расшифровал, как будто они все еще были в latin_1 или utf_8. Возможно, однако, что вы можете иметь latin_1 и utf_8 и любые другие символы, смешанные вместе в имени файла в Windows. Иногда эти персонажи могут появляться в виде ящиков, иногда они просто выглядят искалеченными, а в других случаях они выглядят правильными (акцентированные персонажи и многое другое). Двигаемся дальше.
(2) Python имеет системную кодировку по умолчанию, которая устанавливается при запуске питона и не может быть изменена во время выполнения. См. here. Грязные резюме ... ну вот файл я добавил:
\# sitecustomize.py
\# this file can be anywhere in your Python path,
\# but it usually goes in ${pythondir}/lib/site-packages/
import sys
sys.setdefaultencoding('utf_8')
Эта система кодирования является тот, который привыкает при использовании юникода («ул») функции без каких-либо других параметров кодирования. С другой стороны, python пытается декодировать «str» в unicode на основе системной кодировки по умолчанию.
(3) Если вы используете IDLE или пиктон командной строки, я думаю, что ваша консоль отобразится в соответствии с системной кодировкой по умолчанию. По какой-то причине я использую pydev с eclipse, поэтому мне нужно было войти в мои настройки проекта, отредактировать свойства конфигурации запуска моего тестового скрипта, перейти на вкладку «Общие» и сменить консоль с латинского-1 на utf-8, чтобы Я мог визуально подтвердить, что я делаю, работает.
(4) Если вы хотите иметь несколько тестовых строк, например
test_str = "ó"
в исходном коде, то вы должны сказать питона, какие кодировки Вы используете в этом файле. (FYI: когда я неправильно набранный кодировку я должен был Ctrl-Z, потому что мой файл стал нечитаемым.) Это легко осуществить, поместив линию как и в верхней части вашего кода файла источника:
# -*- coding: utf_8 -*-
Если вы дон «т есть эта информация, попытки питона синтаксического кода в ASCII по умолчанию и так:
SyntaxError: Non-ASCII character '\xf3' in file _redacted_ on line 81, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
После того, как ваша программа работает правильно, или, если вы не используете консоль питона или любую другую консоль, чтобы посмотреть на выходе, то вы, вероятно, действительно заботитесь только о №1 в списке. Системное умолчание и консольное кодирование не так важны, если вам не нужно смотреть на вывод и/или использовать встроенную функцию unicode() (без каких-либо параметров кодирования) вместо функции string.decode(). Я написал демо-функцию, которую я вставляю в дно этого гигантского беспорядка, который, я надеюсь, правильно демонстрирует элементы в моем списке. Вот некоторые из результатов, когда я запускаю символ «-» через демонстрационную функцию, показывая, как различные методы реагируют на символ как на вход.Моя кодировка системы и вывод консоли оба устанавливаются в UTF_8 для этого запуска:
'�' = original char <type 'str'> repr(char)='\xf3'
'?' = unicode(char) ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Теперь я изменить систему и кодирование консольного latin_1, и я получаю этот выход за тот же вход:
'ó' = original char <type 'str'> repr(char)='\xf3'
'ó' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Обратите внимание, что символ «оригинал» отображается правильно, и встроенная функция unicode() работает сейчас.
Теперь я меняю выход на консоль обратно на utf_8.
'�' = original char <type 'str'> repr(char)='\xf3'
'�' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'�' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Здесь все по-прежнему работает так же, как в прошлый раз, но консоль не может отображать вывод правильно. И т. Д. В приведенной ниже функции также отображается дополнительная информация о том, что это и, мы надеемся, поможет кому-то выяснить, где разрыв в их понимании. Я знаю, что вся эта информация находится в других местах и более подробно рассмотрена там, но я надеюсь, что это станет хорошей отправной точкой для тех, кто пытается получить кодирование с помощью python и/или sqlite. Идеи велики, но иногда исходный код может сэкономить вам день или два, пытаясь выяснить, какие функции делают.
Отказ от ответственности: Я не специалист по кодированию, я собрал это вместе, чтобы помочь себе. Я продолжал строить его, когда я, вероятно, начал передавать функции в качестве аргументов, чтобы избежать избыточного кода, поэтому, если можно, я сделаю его более кратким. Кроме того, utf_8 и latin_1 никоим образом не являются единственными схемами кодирования, они - только те два, с которыми я играл, потому что я думаю, что они обрабатывают все, что мне нужно. Добавьте свои собственные схемы кодирования в демонстрационную функцию и протестируйте свой собственный вход.
Еще одна вещь: есть apparently crazy application developers, что затрудняет жизнь в Windows.
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import os
import sys
def encodingDemo(str):
validStrings =()
try:
print "str =",str,"{0} repr(str) = {1}".format(type(str), repr(str))
validStrings += ((str,""),)
except UnicodeEncodeError as ude:
print "Couldn't print the str itself because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print ude
try:
x = unicode(str)
print "unicode(str) = ",x
validStrings+= ((x, " decoded into unicode by the default system encoding"),)
except UnicodeDecodeError as ude:
print "ERROR. unicode(str) couldn't decode the string because the system encoding is set to an encoding that doesn't understand some character in the string."
print "\tThe system encoding is set to {0}. See error:\n\t".format(sys.getdefaultencoding()),
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the unicode(str) because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('latin_1')
print "str.decode('latin_1') =",x
validStrings+= ((x, " decoded with latin_1 into unicode"),)
try:
print "str.decode('latin_1').encode('utf_8') =",str.decode('latin_1').encode('utf_8')
validStrings+= ((x, " decoded with latin_1 into unicode and encoded into utf_8"),)
except UnicodeDecodeError as ude:
print "The string was decoded into unicode using the latin_1 encoding, but couldn't be encoded into utf_8. See error:\n\t",
print ude
except UnicodeDecodeError as ude:
print "Something didn't work, probably because the string wasn't latin_1 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('latin_1') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('utf_8')
print "str.decode('utf_8') =",x
validStrings+= ((x, " decoded with utf_8 into unicode"),)
try:
print "str.decode('utf_8').encode('latin_1') =",str.decode('utf_8').encode('latin_1')
except UnicodeDecodeError as ude:
print "str.decode('utf_8').encode('latin_1') didn't work. The string was decoded into unicode using the utf_8 encoding, but couldn't be encoded into latin_1. See error:\n\t",
validStrings+= ((x, " decoded with utf_8 into unicode and encoded into latin_1"),)
print ude
except UnicodeDecodeError as ude:
print "str.decode('utf_8') didn't work, probably because the string wasn't utf_8 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('utf_8') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",uee
print
print "Printing information about each character in the original string."
for char in str:
try:
print "\t'" + char + "' = original char {0} repr(char)={1}".format(type(char), repr(char))
except UnicodeDecodeError as ude:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), ude)
except UnicodeEncodeError as uee:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), uee)
print uee
try:
x = unicode(char)
print "\t'" + x + "' = unicode(char) {1} repr(unicode(char))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = unicode(char) ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = unicode(char) {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('latin_1')
print "\t'" + x + "' = char.decode('latin_1') {1} repr(char.decode('latin_1'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('latin_1') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('latin_1') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('utf_8')
print "\t'" + x + "' = char.decode('utf_8') {1} repr(char.decode('utf_8'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('utf_8') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('utf_8') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
print
x = 'ó'
encodingDemo(x)
Большое спасибо за ответы ниже и особенно @John Machin за то, что вы так хорошо ответили.
Я имел мою установку терминала для latin1, поэтому я изменил это. Когда вы спрашиваете, что я называю строками Unicode, я использовал метод unicode() на странице, в которой я читал. Я не понимал, что символы Unicode по-прежнему содержат неявное кодирование. Я говорю это правильно? Мне кажется, что unicode ("\ xF3") и "\ xF3" .decode ('latin1') одинаковы при оценке с помощью функции repr(). Является ли это счастливым обстоятельством или является unicode («str»), который всегда возвращает правильное декодирование? Если нет, когда я получаю python str, у которого есть какой-либо возможный набор символов, как я знаю, как его декодировать? –
Еще раз спасибо. Я думаю, ответ на ваш вопрос «Что вы называете строками Unicode? UTF-16?» «независимо от того, какой oacute_unicode». Неужели я пропустил какой-то аспект вашего вопроса, который я должен понимать? Я расшифровал строки, которые я получил от имен файлов, и отправил их в db в этой форме. Я также заказал десять бункеров Пентагона так скоро, что у меня должны быть возможности военного декодирования, и питон будет лишним. –
Я просто проверял, что вы действительно имели в виду объекты юникода Python == какой oacute_unicode, а не UTF-16, который является еще одной возможностью кодирования в базах данных SQLite и которые некоторые называют «Unicode». –