سؤال

أنا أستخدم هذا الرمز للحصول على الإخراج القياسي من برنامج خارجي:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]

يُرجع أسلوب التواصل () مصفوفة من البايتات:

>>> command_stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n'

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

>>> print(command_stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2

اعتقدت أن هذا ما binascii.b2a_qp() الطريقة مخصصة، ولكن عندما جربتها، حصلت على نفس مصفوفة البايت مرة أخرى:

>>> binascii.b2a_qp(command_stdout)
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n'

هل يعرف أحد كيفية تحويل قيمة البايتات مرة أخرى إلى السلسلة؟أعني استخدام "البطاريات" بدلاً من القيام بذلك يدويًا.وأود أن يكون الأمر على ما يرام مع Python 3.

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

المحلول

وتحتاج إلى فك الكائن بايت لإنتاج سلسلة:

>>> b"abcde"
b'abcde'

# utf-8 is used here because it is a very common encoding, but you
# need to use the encoding your data is actually in.
>>> b"abcde".decode("utf-8") 
'abcde'

نصائح أخرى

وأعتقد أن هذه الطريقة سهلة:

bytes_data = [112, 52, 52]
"".join(map(chr, bytes_data))
>> p44

وتحتاج إلى فك شفرة سلسلة بايت وتحويله في ل(يونيكود) سلسلة أحرف.

في بايثون 2

encoding = 'utf-8'
b'hello'.decode(encoding)

في بيثون 3

encoding = 'utf-8'
str(b'hello', encoding)

إذا كنت لا تعرف التشفير، فاستخدم MS-DOS القديم لقراءة الإدخال الثنائي في السلسلة بطريقة متوافقة مع Python 3 وPython 2 cp437 التشفير:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

نظرًا لأن التشفير غير معروف، توقع ترجمة الرموز غير الإنجليزية إلى أحرف cp437 (لا تتم ترجمة الأحرف الإنجليزية، لأنها تتطابق في معظم ترميزات البايت الفردي وUTF-8).

يعد فك تشفير الإدخال الثنائي التعسفي إلى UTF-8 أمرًا غير آمن، لأنك قد تحصل على ما يلي:

>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte

الأمر نفسه ينطبق على latin-1, ، والذي كان شائعًا (افتراضيًا؟) لـ Python 2.انظر النقاط المفقودة في تخطيط صفحة الرموز - هذا هو المكان الذي تختنق فيه بايثون بالسيء السمعة ordinal not in range.

تحديث 20150604:هناك شائعات بأن بايثون 3 لديها surrogateescape استراتيجية الخطأ لتشفير الأشياء إلى بيانات ثنائية دون فقدان البيانات وتعطلها، ولكنها تحتاج إلى اختبارات التحويل [binary] -> [str] -> [binary] للتحقق من صحة كل من الأداء والموثوقية.

تحديث 20170116:بفضل تعليق Nearoo - هناك أيضًا إمكانية لخفض الهروب من جميع وحدات البايت غير المعروفة باستخدام backslashreplace معالج الأخطاء.يعمل هذا فقط مع Python 3، لذلك حتى مع هذا الحل البديل، ستظل تحصل على مخرجات غير متناسقة من إصدارات Python المختلفة:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('utf-8', 'backslashreplace'))

يرى https://docs.python.org/3/howto/unicode.html#python-s-unicode-support للتفاصيل.

تحديث 20170119:قررت تنفيذ فك تشفير الهروب المائل الذي يعمل مع كل من Python 2 و Python 3.ينبغي أن يكون أبطأ ذلك cp437 الحل، ولكن ينبغي أن تنتج نتائج متطابقة في كل إصدار بايثون.

# --- preparation

import codecs

def slashescape(err):
    """ codecs error handler. err is UnicodeDecode instance. return
    a tuple with a replacement for the unencodable part of the input
    and a position where encoding should continue"""
    #print err, dir(err), err.start, err.end, err.object[:err.start]
    thebyte = err.object[err.start:err.end]
    repl = u'\\x'+hex(ord(thebyte))[2:]
    return (repl, err.end)

codecs.register_error('slashescape', slashescape)

# --- processing

stream = [b'\x80abc']

lines = []
for line in stream:
    lines.append(line.decode('utf-8', 'slashescape'))

في بايثون 3, ، الترميز الافتراضي هو "utf-8", ، لذلك يمكنك استخدام مباشرة:

b'hello'.decode()

وهو ما يعادل

b'hello'.decode(encoding="utf-8")

على الجانب الآخر، في بايثون 2, ، الترميز الافتراضي هو ترميز السلسلة الافتراضي.وبالتالي، يجب عليك استخدام:

b'hello'.decode(encoding)

أين encoding هو الترميز الذي تريده

ملحوظة: تمت إضافة دعم لوسائط الكلمات الرئيسية في Python 2.7.

وأعتقد أن ما تريد في الواقع هو هذا:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')
وكانت

الجواب هارون الصحيحة، إلا أن عليك أن تعرف في اي ترميز للاستخدام. وأعتقد أن يستخدم ويندوز 'ويندوز 1252 ". وسوف يهم فقط إذا كان لديك بعض غير عادية (غير أسكي) الأحرف في المحتوى الخاص بك، ولكن بعد ذلك سوف تحدث فرقا.

وبالمناسبة، فإن حقيقة أن يهم هو السبب في أن بيثون انتقلت إلى استخدام نوعين مختلفين عن البيانات الثنائية والنص: أنه لا يمكن تحويل سحرية بينهما لأنه لا يعرف ترميز إلا إذا كنت أقول ذلك ! الطريقة الوحيدة التي من شأنه أن نعرف أن يقرأ وثائق Windows (أو قراءتها هنا).

وتعيين universal_newlines إلى True، أي بمعنى.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

وعلى الرغم الجواب Aaron Maenpaa في تعمل فقط، المستخدم <لأ href = "https://stackoverflow.com/ أسئلة / 33688837 / urllib مقابل بيثون 3/33688948 # comment55151210_33688948 "> طلب مؤخرا :

<اقتباس فقرة>   

هل هناك أي طريقة أكثر بساطة؟ "fhand.read (). فك (" ASCII ")" [...] انها طويلة جدا!

ويمكنك استخدام:

command_stdout.decode()

وdecode() لديه مستوى حجة :

<اقتباس فقرة>   

وcodecs.decode(obj, encoding='utf-8', errors='strict')

لتفسير تسلسل بايت كما نص، عليك أن تعرف ترميز الحرف المطابق:

unicode_text = bytestring.decode(character_encoding)

مثال:

>>> b'\xc2\xb5'.decode('utf-8')
'µ'

الأمر ls قد تنتج الإخراج الذي لا يمكن أن تفسر على أنها نص. أسماء الملفات على يونيكس قد يكون أي تسلسل بايت إلا b'/' القطع والصفر b'\0':

>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()

ومحاولة فك شفرة هذا الحساء بايت باستخدام ترميز UTF-8 يثير UnicodeDecodeError.

ويمكن أن يكون أسوأ من ذلك. قد تفشل فك بصمت وتنتج موجيباكي إذا كنت تستخدم الترميز يتعارض الخطأ:

>>> '—'.encode('utf-8').decode('cp1252')
'—'

وتلف البيانات ولكن يبقى البرنامج غير مدركين أن الفشل حدث.

في عام، ما ترميز الأحرف لاستخدام ليست جزءا لا يتجزأ من تسلسل بايت نفسها. لديك لإيصال هذه المعلومات خارج النطاق. هي بعض نتائج أكثر عرضة من غيرهم وحدة بالتالي chardet موجودة يمكن أن <م> تخمين ترميز الأحرف. وهناك سيناريو بيثون واحد قد تستخدم المحارف متعددة في أماكن مختلفة.


والانتاج ls يمكن تحويلها إلى os.fsdecode() سلسلة بيثون باستخدام الوظيفة التي نجحت حتى ل undecodable أسماء (وأنه يستخدم sys.getfilesystemencoding() والخطأ surrogateescape معالج على يونكس):

import os
import subprocess

output = os.fsdecode(subprocess.check_output('ls'))

لتحصل على بايت الأصلي، هل يمكن استخدام os.fsencode().

إذا قمت بتمرير معلمة universal_newlines=True ثم الاستخدامات subprocess locale.getpreferredencoding(False) لفك بايت على سبيل المثال، يمكن أن يكون cp1252 على ويندوز.

لفك تيار بايت على ذبابة، io.TextIOWrapper() يمكن استخدامها: سبيل المثال

والأوامر المختلفة قد تستخدم المحارف المختلفة الخاصة بهم الناتج مثلا، dir أمر داخلي (cmd) قد تستخدم cp437. لفك لها الإخراج، هل يمكن تمرير ترميز بشكل واضح (بايثون 3.6 +):

output = subprocess.check_output('dir', shell=True, encoding='cp437')

وقد تختلف أسماء من os.listdir() (الذي يستخدم ويندوز يونيكود API) على سبيل المثال، يمكن أن تكون بديلا '\xb6' مع '\x14'-بايثون cp437 خرائط الترميز b'\x14' للسيطرة على الطابع U + 0014 بدلا من U + 00B6 (¶). لدعم أسماء الملفات مع أحرف Unicode التعسفية، انظر فك poweshell الانتاج ربما تحتوي على أحرف يونيكود غير أسكي-إلى سلسلة الثعبان

ومنذ هذا السؤال يسأل فعلا عن انتاج subprocess، لديك نهج أكثر مباشرة متاحة منذ Popen يقبل <وأ href = "https://docs.python.org/3/library/subprocess.html#frequently-used -arguments "يختلط =" noreferrer "> <م> ترميز الكلمة (في بايثون 3.6 +):

>>> from subprocess import Popen, PIPE
>>> text = Popen(['ls', '-l'], stdout=PIPE, encoding='utf-8').communicate()[0]
>>> type(text)
str
>>> print(text)
total 0
-rw-r--r-- 1 wim badger 0 May 31 12:45 some_file.txt

والجواب العامة للمستخدمين الآخرين هو فك بايت إلى النص:

>>> b'abcde'.decode()
'abcde'

ومع عدم وجود حجة، sys.getdefaultencoding() سيتم استخدامها. إذا لم يتم sys.getdefaultencoding() البيانات الخاصة بك، ثم يجب عليك تحديد الترميز صراحة في decode دعوة :

>>> b'caf\xe9'.decode('cp1250')
'café'

إذا يجب عليك الحصول على ما يلي من خلال محاولة decode():

<اقتباس فقرة>   

وAttributeError: "شارع" كائن ليس له السمة 'فك'

ويمكنك أيضا تحديد نوع الترميز مباشرة في الجبس:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

عند العمل مع البيانات من أنظمة ويندوز (مع نهايات خط \r\n)، جوابي هو

String = Bytes.decode("utf-8").replace("\r\n", "\n")

لماذا؟ حاول هذا مع Input.txt متعدد الأسطر:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

وسوف تضاعف كافة النهايات خطك (ل\r\r\n)، مما يؤدي إلى خطوط فارغة إضافية. عادة تطبيع ظائف قراءة النص بايثون نهايات الخط بحيث سلاسل استخدام \n فقط. إذا كنت تتلقى البيانات الثنائية من نظام ويندوز، بيثون لا تكون هناك فرصة للقيام بذلك. وهكذا،

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

وسيتم نسخ الملف الأصلي.

ولقد تقدمت وظيفة لتنظيف قائمة

def cleanLists(self, lista):
    lista = [x.strip() for x in lista]
    lista = [x.replace('\n', '') for x in lista]
    lista = [x.replace('\b', '') for x in lista]
    lista = [x.encode('utf8') for x in lista]
    lista = [x.decode('utf8') for x in lista]

    return lista

لبيثون 3، وهذا هو أكثر أمانا و<م> Pythonic نهج لتحويل من byte إلى string:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): #check if its in bytes
        print(bytes_or_str.decode('utf-8'))
    else:
        print("Object not of byte type")

byte_to_str(b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n')

وإخراج:

total 0
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2
def toString(string):    
    try:
        return v.decode("utf-8")
    except ValueError:
        return string

b = b'97.080.500'
s = '97.080.500'
print(toString(b))
print(toString(s))

إذا كنت تريد تحويل أي بايت، وليس مجرد سلسلة تحويلها إلى بايت:

with open("bytesfile", "rb") as infile:
    str = base64.b85encode(imageFile.read())

with open("bytesfile", "rb") as infile:
    str2 = json.dumps(list(infile.read()))

وهذه ليست فعالة جدا، ولكن. وسوف تتحول صورة 2 ميغابايت في 9 ميغابايت.

http://docs.python.org/3/library/sys. أتش تي أم أل و

لكتابة أو قراءة البيانات الثنائية من / إلى تيارات القياسية، واستخدام المخزن المؤقت ثنائي الأساسي. على سبيل المثال، لكتابة بايت إلى المعياري، استخدم sys.stdout.buffer.write(b'abc').

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