سؤال

كنت أنظر إلى هذا سؤال وبدأت أتساءل ماذا يفعل print في الواقع.

لم أكن قد اكتشفت أبدًا كيفية الاستخدام string.decode() و string.encode() للحصول على سلسلة Unicode "Out" في قذيفة Python التفاعلية بنفس تنسيق الطباعة. لا يهم ما أفعله ، أحصل على أي منهما

  1. unicodeencodeerror أو
  2. السلسلة التي هربت مع تدوين " x ##" ...

هذا هو Python 2.x ، لكنني أحاول بالفعل إصلاح طرقي والاتصال فعليًا print() :)

مثال:

>>> import sys
>>> a = '\xAA\xBB\xCC'
>>> print(a)
ª»Ì
>>> a.encode(sys.stdout.encoding)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0xaa in position 0: ordinal not in range(128)
>>> a.decode(sys.stdout.encoding)
u'\xaa\xbb\xcc'

تعديل:

لماذا أسأل هذا؟ لقد سئمت من encode() الأخطاء وأدركت ذلك منذ ذلك الحين print يمكن أن تفعل ذلك (على الأقل في القشرة التفاعلية). أعلم أن يجب أن تكون وسيلة للقيام بالتشفير بطريقة سحرية بصورة صحيحة, ، عن طريق حفر المعلومات ما هو الترميز لاستخدامه من مكان ما ...

معلومات إضافية: أنا أقوم بتشغيل Python 2.4.3 (#1 ، 3 سبتمبر 2009 ، 15:37:12) [GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] على Linux2

>>> sys.stdin.encoding
'ISO-8859-1'
>>> sys.stdout.encoding
'ISO-8859-1'

ومع ذلك ، فإن النتائج هي نفسها مع Python 2.6.2 (R262: 71600 ، سبتمبر 8 2009 ، 13:06:43) على صندوق Linux نفسه.

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

المحلول

تعديل: (التغييرات الرئيسية بين هذا التحرير والآخر ... ملاحظة: أنا أستخدم Python 2.6.4 على مربع Ubuntu.)

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

>>> print '\xaa\xbb\xcc'
��

هل حاولت إدخال ª »ì مباشرة من المحطة؟ في محطة Linux باستخدام UTF-8 كما الترميز ، يتم قراءة هذا بالفعل في ستة بايت ، والتي يمكن بعد ذلك صنعها لتبدو مثل ثلاثة chars بمساعدة decode طريقة:

>>> 'ª»Ì'
'\xc2\xaa\xc2\xbb\xc3\x8c'
>>> 'ª»Ì'.decode(sys.stdin.encoding)
u'\xaa\xbb\xcc'

لذلك '\xaa\xbb\xcc' الحرفي فقط منطقي إذا قمت بفك تشفيره باعتبارها حرفية لاتينية 1 (حسنًا ، في الواقع ، يمكنك استخدام ترميز مختلف يتفق مع Latin-1 على الشخصيات ذات الصلة). أما بالنسبة لل print "مجرد العمل" في قضيتك ، بالتأكيد لا بالنسبة لي - كما ذكر أعلاه.

يتم تفسير ذلك بحقيقة أنه عند استخدام سلسلة حرفية غير مسبوقة بـ u -- بمعنى آخر "asdf" عوضا عن u"asdf" -ستستخدم السلسلة الناتجة بعض الترميز غير uniCode. لا؛ في الواقع ، سيكون كائن السلسلة نفسه هو الترميز ، وسيتعين عليك معاملته كما لو كان مشفرًا بترميز x ، للقيمة الصحيحة لـ x. هذه الفكرة الأساسية تقودني إلى ما يلي:

a = '\xAA\xBB\xCC'
a.decode('latin1')
# result: u'\xAA\xBB\xCC'
print(a.decode('latin1'))
# output: ª»Ì

لاحظ عدم وجود أخطاء فك التشفير والإخراج المناسب (الذي أتوقع أن أبقى مناسبًا في أي صندوق آخر). من الواضح أن السلسلة الحرفية الخاصة بك يمكن أن تكون منطقية من قبل بيثون ، ولكن ليس من دون بعض المساعدة.

هل هذا يساعد؟ (على الأقل في فهم كيفية عمل الأشياء ، إن لم يكن في جعل التعامل مع الترميزات أسهل ...)


الآن لبعض البتات المضحكة مع بعض القيمة التوضيحية (نأمل)! هذا يفي بالغرض بالنسبة لي:

sys.stdout.write("\xAA\xBB\xCC".decode('latin1').encode(sys.stdout.encoding))

يؤدي تخطي إما فك الرمز أو جزء التشفير إلى استثناء مرتبط بـ UNICODE. من الناحية النظرية ، هذا أمر منطقي ، حيث أن هناك حاجة إلى فك الرموز الأولى لتحديد الشخصيات الموجودة في السلسلة المحددة (الشيء الوحيد الواضح للوهلة الأولى هو ماذا بايت هناك - فكرة Python 3 عن وجود سلاسل (Unicode) للشخصيات والبايتات ، بشكل جيد ، تبدو فجأة معقولة بشكل رائع) ، بينما هناك حاجة إلى الترميز بحيث يحترم الإخراج تشفير دفق الإخراج. الآن هذا

sys.stdout.write("ąöî\n".decode(sys.stdin.encoding).encode(sys.stdout.encoding))

يعمل أيضًا كما هو متوقع ، لكن الشخصيات تأتي فعليًا من لوحة المفاتيح وبالتالي يتم ترميزها بالفعل مع ترميز stdin ... أيضًا ،

ord('ą'.decode('utf-8').encode('latin2'))

إرجاع 177 الصحيح (ترميز الإدخال الخاص بي هو UTF-8) ، ولكن ' xc4 x85'.encode (' latin2 ') لا معنى له للثعب X85 'والأرقام التي تفيد بأن تجربة رمز "ASCII" هي أفضل ما يمكن أن تفعله.


الجواب الأصلي:

بت من الصلة من مستندات Python (للإصدار 2.6.4) يقول ذلك print(obj) من المفترض أن تطبع السلسلة المقدمة str(obj). أفترض أنه يمكنك بعد ذلك لفه في مكالمة unicode (كما في unicode(str(obj))) للحصول على سلسلة Unicode - أو يمكنك فقط استخدام Python 3 وتبادل هذا الإزعاج المعين لبضعين مختلفين. ؛-)

بالمناسبة ، هذا يدل على أنه يمكنك معالجة نتيجة printجي كائن تمامًا كما يمكنك معالجة نتيجة الاتصال str على كائن ، هذا هو عن طريق العبث مع __str__ طريقة. مثال:

class Foo(object):
    def __str__(self):
        return "I'm a Foo!"

print Foo()

أما بالنسبة للتنفيذ الفعلي ل print, ، أتوقع أن يكون هذا مفيدًا على الإطلاق ، ولكن إذا كنت هل حقا تريد أن تعرف ما يحدث ... إنه في الملف Python/bltinmodule.c في مصادر بيثون (أنا أبحث في الإصدار 2.6.4). ابحث عن خط يبدأ بـ builtin_print. انها في الواقع واضحة تماما ، لا السحر يحدث هناك. :-)

نأمل أن يجيب هذا على سؤالك ... ولكن إذا كان لديك مشكلة أكثر غموضًا ، فأنا في عداد المفقودين تمامًا ، سأقوم بالتعليق ، سأقوم بمحاولة ثانية. أيضًا ، أفترض أننا نتعامل مع Python 2.x ؛ وإلا أعتقد أنه لن يكون لدي تعليق مفيد.

نصائح أخرى

print() الاستخدامات sys.stdout.encoding لتحديد ما يمكن أن تفهمه وحدة التحكم في الإخراج ، ثم يستخدم هذا الترميز في المكالمة إلى str.encode().

تحرير] إذا كنت انظر إلى المصدر, ، تحصل sys.stdout ثم يدعو:

PyFile_WriteObject(PyTuple_GetItem(args, i), file,
                 Py_PRINT_RAW);

أعتقد أن السحر في Py_PRINT_RAW لكن المصدر فقط يقول:

    if (flags & Py_PRINT_RAW) {
    value = PyObject_Str(v);
    }

لذلك لا السحر هنا. حلقة على الحجج مع sys.stdout.write(str(item)) يجب أن تفعل الخدعة.

>>> import sys
>>> a = '\xAA\xBB\xCC'
>>> print(a)
ª»Ì

الجميع print يفعل هنا هو كتابة الخام بايت ل sys.stdout. السلسلة a هي سلسلة من البايتات ، وليس أحرف Unicode.

لماذا أسأل هذا؟ لقد سئمت من أخطاء encode () وأدركت أنه نظرًا لأن الطباعة يمكن أن تفعل ذلك (على الأقل في القشرة التفاعلية). أعلم أنه يجب أن يكون وسيلة للقيام بطريقة سحرية للترميز بشكل صحيح ، من خلال حفر المعلومات التي ترميزها لاستخدامها من مكان ما ...

للأسف لا ، print لا يفعل أي شيء على الإطلاق سحري هنا. تقوم بتسليمها بعض البايتات ، فهي تفريغ البايت إلى stdout.

ليستخدم .encode() و .decode() بشكل صحيح ، تحتاج إلى فهم الفرق بين البايت والشخصيات ، وأخشى أن يتعين عليك معرفة الترميز الصحيح للاستخدام.

import sys

source_file_encoding = 'latin-1' # if there is no -*- coding: ... -*- line

a = '\xaa\xbb\xcc' # raw bytes that represent string in source_file_encoding

# print bytes, my terminal tries to interpret it as 'utf-8'
sys.stdout.write(a+'\n') 
# -> ��

ua = a.decode(source_file_encoding)
sys.stdout.write(ua.encode(sys.stdout.encoding)+'\n')
# -> ª»Ì

يرى تحديد ترميزات شفرة مصدر بيثون

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