سؤال

بدأت بمحاولة تخزين الأوتار في SQLite باستخدام Python ، وحصلت على الرسالة:

sqlite3.programmingerror: يجب ألا تستخدم بايت 8 بت ما لم تستخدم text_factory يمكن أن يفسر 8 بت بايت (مثل text_factory = str). يوصى بشدة أن تقوم بدلاً من ذلك بتبديل التطبيق إلى سلاسل Unicode.

حسنًا ، لقد تحولت إلى سلاسل Unicode. ثم بدأت في تقديم الرسالة:

sqlite3.operationalerror: لا يمكن فك تشفير العمود UTF-8 'tag_artist' مع نص 'sigur rós'

عند محاولة استرداد البيانات من DB. المزيد من البحث وبدأت في ترميزه في UTF8 ، ولكن بعد ذلك يبدأ "Sigur Rós" في أن تبدو مثل "Sigur Rãs"

ملاحظة: تم تعيين وحدة التحكم الخاصة بي على عرضها في "LATIN_1" كما أشار John Machin.

ما يعطي؟ بعد القراءة هذه, ، واصفًا نفس الموقف الذي أتواجد فيه بالضبط ، يبدو كما لو أن النصيحة هي تجاهل النصيحة الأخرى واستخدام البايتات 8 بت بعد كل شيء.

لم أكن أعرف الكثير عن Unicode و UTF قبل أن أبدأ هذه العملية. لقد تعلمت قليلاً في الساعات القليلة الماضية ، لكنني ما زلت جاهلًا بما إذا كانت هناك طريقة لتحويل "ó" من اللاتيني -1 بشكل صحيح إلى UTF-8 وعدم إخراجها. إذا لم يكن هناك ، فلماذا سيفصح SQLite "بشدة" ، أقوم بتبديل طلبي إلى سلاسل Unicode؟


سأقوم بتحديث هذا السؤال بملخص وبعض مثال رمز لكل ما تعلمته خلال الـ 24 ساعة الماضية حتى يتمكن شخص ما في حذائي من وجود دليل سهل (ER). إذا كانت المعلومات التي نشرتها خاطئة أو مضللة بأي شكل من الأشكال ، فيرجى إخباري وسأقوم بتحديثها ، أو يمكن لأحدكم كبار اللاعبين تحديث.


ملخص للإجابات

اسمحوا لي أولاً أن أذكر الهدف كما أفهمه. الهدف من معالجة الترميزات المختلفة ، إذا كنت تحاول التحويل بينها ، هو فهم ماهية تشفير المصدر ، ثم قم بتحويله إلى Unicode باستخدام هذا المصدر ، ثم تحويله إلى الترميز المطلوب. Unicode هي قاعدة والترميزات هي تعيينات مجموعات فرعية من تلك القاعدة. يحتوي UTF_8 على مساحة لكل حرف في Unicode ، ولكن نظرًا لأنها ليست في نفس المكان ، على سبيل المثال ، Latin_1 ، فإن سلسلة مشفرة في UTF_8 وإرسالها إلى وحدة تحكم Latin_1 لن تبدو بالطريقة التي تتوقعها. في بيثون ، تبدو عملية الوصول إلى Unicode وإلى ترميز آخر:

str.decode('source_encoding').encode('desired_encoding')

أو إذا كان STR بالفعل في Unicode

str.encode('desired_encoding')

بالنسبة إلى SQLite ، لم أكن أرغب بالفعل في تشفيره مرة أخرى ، أردت فك تشفيره وتركه بتنسيق Unicode. فيما يلي أربعة أشياء قد تحتاج إلى أن تكون على دراية بها أثناء محاولتك العمل مع Unicode والترميزات في Python.

  1. ترميز السلسلة التي تريد العمل معها ، والتشفير الذي تريد الحصول عليه.
  2. ترميز النظام.
  3. ترميز وحدة التحكم.
  4. ترميز الملف المصدر

التفصيل:

(1) عند قراءة سلسلة من مصدر ، يجب أن يكون لها بعض الترميز ، مثل LATIN_1 أو UTF_8. في حالتي ، أحصل على سلاسل من أسماء الملفات ، لذلك لسوء الحظ ، يمكن أن أحصل على أي نوع من الترميز. يستخدم Windows XP UCS-2 (نظام Unicode) كنوع سلسلة أصلي ، والذي يبدو وكأنه غش بالنسبة لي. لحسن الحظ بالنسبة لي ، لن تتكون الشخصيات الموجودة في معظم أسماء الملفات من أكثر من نوع ترميز مصدر واحد ، وأعتقد أن كل ما عندي إما لاتين_1 تمامًا ، أو UTF_8 تمامًا ، أو مجرد ASCII عادي (وهو مجموعة فرعية من كلاهما هؤلاء). لذلك قرأتها للتو وفك تشفيرها كما لو كانوا لا يزالون في Latin_1 أو UTF_8. من الممكن ، مع ذلك ، أن يكون لديك LATIN_1 و UTF_8 وأي أحرف أخرى تم خلطها معًا في اسم ملف على Windows. في بعض الأحيان ، يمكن أن تظهر هذه الشخصيات كمربعات ، وفي أوقات أخرى تبدو مشوهة ، وفي أحيان أخرى تبدو صحيحة (شخصيات معلنة وما إلى ذلك). الانتقال.

(2) يحتوي Python على نظام ترميز افتراضي يتم تعيينه عندما يبدأ Python ولا يمكن تغييره أثناء وقت التشغيل. يرى هنا للتفاصيل. ملخص قذر ... حسنًا ، هذا الملف الذي أضفته:

\# 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')  

ترميز النظام هذا هو الذي يتم استخدامه عند استخدام وظيفة Unicode ("STR") دون أي معلمات ترميز أخرى. لقول ذلك بطريقة أخرى ، يحاول Python فك تشفير "STR" إلى Unicode استنادًا إلى ترميز النظام الافتراضي.

(3) إذا كنت تستخدم IDLE أو Python سطر الأوامر ، فأعتقد أن وحدة التحكم الخاصة بك ستعرض وفقًا لترميز النظام الافتراضي. أنا أستخدم Pydev مع Eclipse لسبب ما ، لذلك اضطررت إلى الذهاب إلى إعدادات المشروع الخاصة بي ، وتحرير خصائص تكوين التشغيل في البرنامج النصي للاختبار ، والانتقال إلى علامة التبويب المشتركة ، وتغيير وحدة التحكم من Latin-1 إلى UTF-8 كان بإمكاني تأكيد ما كنت أفعله بصريًا.

(4) إذا كنت ترغب في الحصول على بعض سلاسل الاختبار ، على سبيل المثال

test_str = "ó"

في رمز المصدر الخاص بك ، سيتعين عليك إخبار Python بنوع الترميز الذي تستخدمه في هذا الملف. (لمعلوماتك: عندما أخطأت في ترميز ، اضطررت إلى Ctrl-Z لأن ملفي أصبح غير قابل للقراءة.) يتم تحقيق ذلك بسهولة عن طريق وضع سطر مثل ذلك في أعلى ملف رمز المصدر الخاص بك:

# -*- coding: utf_8 -*-

إذا لم يكن لديك هذه المعلومات ، فإن Python يحاول تحليل الكود الخاص بك على أنه 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

بمجرد أن يعمل البرنامج بشكل صحيح ، أو إذا كنت لا تستخدم وحدة التحكم في Python أو أي وحدة تحكم أخرى للنظر في الإخراج ، فمن المحتمل أن تهتم فقط بالرقم 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 ليسا بأي حال مخططات الترميز الوحيدة ، فهي مجرد الاثنين اللذين كنت ألعب معه لأنني أعتقد أنهما يتعاملان مع كل ما أحتاجه. أضف مخططات الترميز الخاصة بك إلى وظيفة العرض التجريبي واختبار المدخلات الخاصة بك.

شيء آخر: هناك يبدو أن مطوري التطبيقات المجنونة جعل الحياة صعبة في النوافذ.

#!/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 للرد عليها تمامًا.

هل كانت مفيدة؟

المحلول

ما زلت جاهلًا بما إذا كانت هناك طريقة لتحويل "ó" من اللاتيني -1 بشكل صحيح

repr () و Unicodedata.name () هما أصدقاؤك عندما يتعلق الأمر بتصحيح مثل هذه المشكلات:

>>> oacute_latin1 = "\xF3"
>>> oacute_unicode = oacute_latin1.decode('latin1')
>>> oacute_utf8 = oacute_unicode.encode('utf8')
>>> print repr(oacute_latin1)
'\xf3'
>>> print repr(oacute_unicode)
u'\xf3'
>>> import unicodedata
>>> unicodedata.name(oacute_unicode)
'LATIN SMALL LETTER O WITH ACUTE'
>>> print repr(oacute_utf8)
'\xc3\xb3'
>>>

إذا قمت بإرسال Oacute_utf8 إلى محطة تم إعدادها لـ Latin1 ، فستحصل على tilde تليها SuperScript-3.

تحولت إلى سلاسل يونيكود.

ماذا تسمي سلاسل يونيكود؟ UTF-16؟

ما يعطي؟ بعد قراءة هذا ، وصف نفس الموقف بالضبط الذي أنا فيه ، يبدو كما لو أن النصيحة هي تجاهل النصيحة الأخرى واستخدام بايت 8 بت بعد كل شيء.

لا أستطيع أن أتخيل كيف يبدو ذلك لك. كانت القصة التي تم نقلها هي أن كائنات Unicode في Python و UTF-8 ترميز في قاعدة البيانات كانت هي السبيل للذهاب. ومع ذلك ، أجاب مارتن على السؤال الأصلي ، مع إعطاء طريقة ("مصنع نص") ليتمكن المرجع من استخدام Latin1 - هذا لم يشكل توصية!

تحديث رداً على هذه الأسئلة الإضافية التي أثيرت في تعليق:

لم أفهم أن أحرف Unicode لا تزال تحتوي على ترميز ضمني. هل أقول هذا الحق؟

لا. الترميز هو رسم خرائط بين Unicode وشيء آخر ، والعكس صحيح. لا يحتوي حرف Unicode على ترميز ، ضمنيًا أو غير ذلك.

يبدو لي مثل Unicode (" xf3") و " xf3" .decode ('latin1') هي نفسها عند تقييمها مع repr ().

يقول ما؟ لا يبدو لي:

>>> unicode("\xF3")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf3 in position 0: ordinal
not in range(128)
>>> "\xF3".decode('latin1')
u'\xf3'
>>>

ربما كنت تعني: u'\xf3' == '\xF3'.decode('latin1') ... هذا صحيح بالتأكيد.

صحيح أيضا أن unicode(str_object, encoding) يفعل نفس الشيء str_object.decode(encoding) ... بما في ذلك النفخ عند توفير ترميز غير مناسب.

هل هذا ظرف سعيد

أن أول 256 حرفًا في Unicode هي نفسها ، رمز الكود ، لأن 256 حرفًا في Latin1 هي فكرة جيدة. نظرًا لأن جميع أحرف Latin1 المحتملة 256 يتم تعيينها إلى Unicode ، فهذا يعني أن أي بايت 8 بت ، يمكن فك تشفير أي كائن Python Str في Unicode دون استثناء. هذا هو ما ينبغي أن يكون.

ومع ذلك ، هناك بعض الأشخاص الذين يخلطون بين مفهومين منفصلين تمامًا: "يتم تشغيل البرنامج النصي الخاص بي إلى الانتهاء دون أي استثناءات مثبتة" و "البرنامج النصي خالي من الأخطاء". بالنسبة لهم ، Latin1 هو "كمين ووهبة".

بمعنى آخر ، إذا كان لديك ملف مشفر فعليًا في CP1252 أو GBK أو Koi8 -U أو أي شيء آخر ، فلن يتم فك تشفيره باستخدام LATIN1 ، فلن يكون Unicode الناتج قمامة تمامًا و python (أو أي لغة أخرى) - ليس لديه أي وسيلة لمعرفة أنك قد ارتكبت سخافة.

أم أن Unicode ("STR") ستعيد دائمًا فك التشفير الصحيح؟

تمامًا مثل هذا ، مع وجود ترميز افتراضي هو ASCII ، سيعيد Unicode الصحيح إذا تم ترميز الملف فعليًا في ASCII. خلاف ذلك ، سوف ينفجر.

وبالمثل ، إذا قمت بتحديد الترميز الصحيح ، أو الذي يعد مجموعة من الترميز الصحيح ، فستحصل على النتيجة الصحيحة. وإلا ستحصل على رطانة أو استثناء.

بأختصار، الجواب هو كلا.

إذا لم يكن الأمر كذلك ، عندما أتلقى Python Str الذي يحتوي على أي حرف محتمل ، كيف أعرف كيفية فك تشفيره؟

إذا كان كائن STR هو مستند XML صالح ، فسيتم تحديده في المقدمة. الافتراضي هو UTF-8. إذا كانت صفحة ويب تم إنشاؤها بشكل صحيح ، فيجب تحديدها في المقدمة (ابحث عن "Charset"). لسوء الحظ ، يجب أن يكون العديد من كتاب صفحات الويب من خلال أسنانهم (ISO-8859-1 AKA Latin1 ، Windows-1252 ويعرف أيضًا باسم CP1252 ؛ لا تضيع الموارد التي تحاول فك تشفير GB2312 ، استخدم GBK بدلاً من ذلك). يمكنك الحصول على أدلة من جنسية/لغة الموقع.

UTF-8 يستحق دائمًا المحاولة. إذا كانت البيانات هي ASCII ، فسيعمل بشكل جيد ، لأن ASCII هي مجموعة فرعية من UTF8. من المؤكد أن سلسلة من النصوص التي تمت كتابتها باستخدام أحرف غير ASCII وتم ترميزها في ترميز بخلاف UTF8 ستفشل تقريبًا باستثناء إذا حاولت فك تشفيرها كـ UTF8.

كل ما سبق الاستدلال والمزيد والكثير من الإحصائيات مغلفة في شارديت, ، وحدة لتخمين ترميز الملفات التعسفية. عادة ما يعمل بشكل جيد. ومع ذلك ، لا يمكنك جعل البرمجيات مقاومة للحبل. على سبيل المثال ، إذا قمت بتسلسل ملفات البيانات التي كتبت بعضها مع ترميز A وبعضها مع الترميز B ، وتغذية النتيجة إلى Chardet ، فمن المحتمل أن تكون الإجابة ترميز C مع انخفاض مستوى الثقة على سبيل المثال 0.8. تحقق دائمًا من جزء الثقة من الإجابة.

إذا فشل كل شيء آخر:

(1) حاول السؤال هنا ، مع عينة صغيرة من مقدمة بياناتك ... print repr(your_data[:400]) ... وأي معلومات ضمانية عن مصدرها الذي لديك.

(2) البحوث الروسية الأخيرة في تقنيات لاستعادة كلمات المرور المنسية يبدو أنه قابل للتطبيق تمامًا على استنتاج ترميزات غير معروفة.

تحديث 2 راجع للشغل ، أليس الوقت قد فتحت سؤالًا آخر؟-)

شيء آخر: هناك أحرف على ما يبدو يستخدمها Windows كحارس معين لبعض الأحرف التي ليست هي Unicode الصحيحة لهذا الحرف ، لذلك قد تضطر إلى تعيين تلك الأحرف إلى الأحرف الصحيحة إذا كنت ترغب توقع تلك الشخصيات في المكان الصحيح.

إنها ليست نوافذ تفعل ذلك ؛ إنها مجموعة من مطوري التطبيقات المجنونة. قد يكون لديك أكثر مفهومًا لم يتم إعادة صياغته ولكنك نقلت الفقرة الافتتاحية لمقال Effbot الذي أشرت إليه:

تضيف بعض التطبيقات أحرف CP1252 (Windows أو Western Europe) إلى المستندات التي تم تمييزها باسم ISO 8859-1 (Latin 1) أو غيرها من الترميزات. هذه الأحرف غير صالحة أحرف ISO-8859-1 ، وقد تتسبب في جميع أنواع المشاكل في المعالجة وعرض التطبيقات.

خلفية:

تم تعيين النطاق U+0000 إلى U+001F الشامل في Unicode كـ "أحرف التحكم C0". هذه موجودة أيضا في ASCII و LATIN1 ، مع نفس المعاني. وهي تشمل الأشياء العائلية مثل عودة النقل ، وتغذية الخط ، والجرس ، والمسافة الخلفية ، وعلامة التبويب ، وغيرها التي يتم استخدامها.

تم تعيين النطاق U+0080 إلى U+009F الشامل في Unicode كـ "أحرف التحكم C1". هذه موجودة أيضًا في Latin1 ، وتشمل 32 حرفًا لا يمكن لأي شخص خارج Unicode.org أن يتخيل أي استخدام ممكن له.

وبالتالي ، إذا قمت بتشغيل عدد ترددات الأحرف على بيانات Unicode أو Latin1 ، وعثرت على أي أحرف في هذا النطاق ، فإن بياناتك تالف. لا يوجد حل عالمي. ذلك يعتمد على كيفية تالف. الشخصيات مايو احصل على نفس المعنى مثل أحرف CP1252 في نفس المواضع ، وبالتالي سيعمل حل Effbot. في حالة أخرى كنت أبحث عنها مؤخرًا ، يبدو أن الأحرف المراوغة ناجمة عن تسلسل الملفات النصية المشفرة في UTF-8 وترميز آخر يجب استنتاجه بناءً على ترددات الحروف في اللغة (البشرية) كانت الملفات كتبت في.

نصائح أخرى

UTF-8 هو الترميز الافتراضي لقواعد بيانات SQLite. هذا يظهر في مواقف مثل "SELECT CAST (X'52C3B373" كنص) ؛ ". ومع ذلك ، فإن مكتبة SQLite C لا تتحقق فعليًا مما إذا كانت السلسلة التي تم إدخالها في DB صالحة UTF-8.

إذا قمت بإدخال كائن Python Unicode (أو كائن STR في 3.x) ، فسيقوم مكتبة Python SQLite3 تلقائيًا بتحويلها إلى UTF-8. ولكن إذا قمت بإدخال كائن STR ، فسيكون ذلك فقط تولى القيام السلسلة هي UTF-8 ، لأن Python 2.x "Str" لا يعرف ترميزه. هذا هو أحد الأسباب لتفضيل سلاسل Unicode.

ومع ذلك ، لا يساعدك ذلك إذا تم كسر بياناتك لتبدأ.

لإصلاح بياناتك ، افعل

db.create_function('FIXENCODING', 1, lambda s: str(s).decode('latin-1'))
db.execute("UPDATE TheTable SET TextColumn=FIXENCODING(CAST(TextColumn AS BLOB))")

لكل عمود نص في قاعدة البيانات الخاصة بك.

لقد أصلحت هذه المشكلة pysqlite عن طريق الإعداد:

conn.text_factory = lambda x: unicode(x, 'utf-8', 'ignore')

بشكل افتراضي تم تعيين Text_Factory على Unicode () ، والذي سيستخدم الترميز الافتراضي الحالي (ASCII على الجهاز الخاص بي)

بالطبع هناك. لكن بياناتك مكسورة بالفعل في قاعدة البيانات ، لذلك ستحتاج إلى إصلاحها:

>>> print u'Sigur Rós'.encode('latin-1').decode('utf-8')
Sigur Rós

مشاكل Unicode الخاصة بي مع Python 2.x (Python 2.7.6 لتكون محددة) إصلاح هذا:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

كما أنه حل الخطأ الذي ذكرته مباشرة في بداية المنشور:

sqlite3.programmingerror: يجب ألا تستخدم بايت 8 بت ما لم ...

تعديل

sys.setdefaultencoding هو الاختراق القذر. نعم ، يمكن أن يحل مشكلات UTF-8 ، ولكن كل شيء يأتي بسعر. لمزيد من التفاصيل ، يرجى الرجوع إلى الروابط التالية:

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top