python - बाइट्स को स्ट्रिंग में कनवर्ट करें?




string python-3.x (10)

मैं बाहरी कोड से मानक आउटपुट प्राप्त करने के लिए इस कोड का उपयोग कर रहा हूं:

>>> 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'

क्या कोई जानता है कि बाइट्स वैल्यू को स्ट्रिंग में वापस कैसे परिवर्तित करें? मेरा मतलब है, इसे मैन्युअल रूप से करने के बजाय "बैटरी" का उपयोग करना। और मैं इसे पायथन 3 के साथ ठीक करना चाहता हूं।


आपको बाइट स्ट्रिंग को डीकोड करने और उसे एक वर्ण (यूनिकोड) स्ट्रिंग में बदलने की आवश्यकता है।

b'hello'.decode(encoding)

या

str(b'hello', encoding)

टेक्स्ट के रूप में बाइट अनुक्रम की व्याख्या करने के लिए, आपको संबंधित वर्ण एन्कोडिंग को जानना होगा:

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()

यूटीएफ -8 एन्कोडिंग का उपयोग करके इस तरह के बाइट सूप को डीकोड करने का प्रयास UnicodeDecodeError उठाता है।

यह बदतर हो सकता है। डीकोडिंग चुपचाप विफल हो सकती है और यदि आप गलत असंगत एन्कोडिंग का उपयोग करते हैं तो mojibake उत्पादन करें:

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

डेटा दूषित हो गया है लेकिन आपका प्रोग्राम इस बात से अनजान है कि विफलता आई है।

सामान्य रूप से, उपयोग करने के लिए कौन सी वर्ण एन्कोडिंग बाइट अनुक्रम में एम्बेडेड नहीं है। आपको इस जानकारी को आउट-ऑफ-बैंड से संवाद करना होगा। कुछ परिणाम दूसरों की तुलना में अधिक संभावनाएं हैं और इसलिए chardet मॉड्यूल मौजूद है जो वर्ण एन्कोडिंग का अनुमान लगा सकता है। एक पाइथन लिपि विभिन्न स्थानों में एकाधिक वर्ण एन्कोडिंग का उपयोग कर सकती है।

ls आउटपुट को os.fsdecode() फ़ंक्शन का उपयोग करके एक पायथन स्ट्रिंग में परिवर्तित किया जा सकता है जो अनावश्यक फ़ाइल नामों के लिए भी सफल होता है (यह sys.getfilesystemencoding() और यूनिक्स पर sys.getfilesystemencoding() त्रुटि हैंडलर का उपयोग करता है):

import os
import subprocess

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

मूल बाइट्स प्राप्त करने के लिए, आप os.fsencode() उपयोग कर सकते हैं।

यदि आप universal_newlines=True पैरामीटर पास करते हैं तो subprocess बाइट्स को डीकोड करने के लिए locale.getpreferredencoding(False) का उपयोग करता है, उदाहरण के लिए, यह Windows पर locale.getpreferredencoding(False) हो सकता है।

बाइट स्ट्रीम ऑन द फ्लाई को डीकोड करने के लिए, io.TextIOWrapper() का उपयोग किया जा सकता है: example ।

विभिन्न आदेश उनके आउटपुट के लिए अलग-अलग वर्ण एन्कोडिंग का उपयोग कर सकते हैं उदाहरण के लिए, dir आंतरिक कमांड ( cmd ) cp437 का उपयोग कर सकता है। अपने आउटपुट को डीकोड करने के लिए, आप एन्कोडिंग को स्पष्ट रूप से पास कर सकते हैं (पायथन 3.6+):

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

फ़ाइल नाम os.listdir() से भिन्न हो सकते हैं (जो विंडोज यूनिकोड एपीआई का उपयोग करता है) उदाहरण के लिए, '\xb6' को '\x14' साथ प्रतिस्थापित किया जा सकता है- पायथन के सीपी 437 कोडेक मानचित्र b'\x14' यू के बजाय चरित्र यू + 0014 को नियंत्रित करने के लिए + 00 बी 6 (¶)। मनमानी यूनिकोड वर्णों के साथ फ़ाइल नामों का समर्थन करने के लिए, डीकोड पाउशेल आउटपुट देखें संभवतः गैर-एसीआई यूनिकोड वर्णों को एक पायथन स्ट्रिंग में


पायथन 3 में आप सीधे उपयोग कर सकते हैं:

b'hello'.decode()

जो बराबर है

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

यहां डिफ़ॉल्ट एन्कोडिंग "utf-8" है, या आप इसे देख सकते हैं:

>> import sys
>> sys.getdefaultencoding()

मुझे लगता है कि आप वास्तव में क्या चाहते हैं यह है:

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

हारून का जवाब सही था, सिवाय इसके कि आपको यह जानने की जरूरत है कि किस एन्कोडिंग का उपयोग करना है। और मेरा मानना ​​है कि विंडोज़ 'विंडोज -1252' का उपयोग करता है। यह केवल तभी मायने रखता है यदि आपके पास आपकी सामग्री में कुछ असामान्य (गैर-एएससीआई) वर्ण हैं, लेकिन फिर इससे कोई फर्क पड़ेगा।

वैसे, तथ्य यह है कि इससे कोई फर्क नहीं पड़ता कि पाइथन बाइनरी और टेक्स्ट डेटा के लिए दो अलग-अलग प्रकारों का उपयोग करने के लिए स्थानांतरित हो गया है: यह उनके बीच जादुई रूप से परिवर्तित नहीं हो सकता है क्योंकि जब तक आप इसे नहीं बताते हैं तो यह एन्कोडिंग नहीं जानता! एकमात्र तरीका आपको पता होगा कि विंडोज दस्तावेज़ को पढ़ना है (या इसे यहां पढ़ें)।


मैंने एक सूची साफ करने के लिए एक समारोह बनाया

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 और पायथन 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 वर्णों में अनुवाद करने की cp437 (अंग्रेजी वर्णों का अनुवाद नहीं किया जाता है, क्योंकि वे अधिकतर बाइट एन्कोडिंग और यूटीएफ -8 में मेल खाते हैं)।

यूटीएफ -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 पर लागू होता है, जो पाइथन 2 के लिए लोकप्रिय (डिफ़ॉल्ट?) था। कोडपेज लेआउट में लापता बिंदु देखें - यह वह जगह है जहां पाइथन कुख्यात ordinal not in range साथ ordinal not in range

अद्यतन 20150604 : अफवाहें हैं कि पाइथन 3 में डेटा हानि और दुर्घटनाओं के बिना बाइनरी डेटा में एन्कोडिंग सामग्री के लिए सरोगेटेस्केप त्रुटि रणनीति है, लेकिन प्रदर्शन और विश्वसनीयता दोनों को सत्यापित करने के लिए इसे रूपांतरण परीक्षण [binary] -> [str] -> [binary] है।

अद्यतन 20170116 : पासू द्वारा टिप्पणी करने के लिए धन्यवाद - backslashreplace त्रुटि हैंडलर के साथ सभी अज्ञात बाइट्स से बचने की संभावना भी है। यह केवल पायथन 3 के लिए काम करता है, इसलिए इस कामकाज के साथ भी आप विभिन्न पायथन संस्करणों से असंगत आउटपुट प्राप्त करेंगे:

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 : मैंने स्लैश एस्केपिंग डिकोड को लागू करने का निर्णय लिया जो कि पाइथन 2 और पायथन 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'))

विंडोज सिस्टम से डेटा के साथ काम करते समय ( \r\n लाइन एंडिंग के साथ), मेरा जवाब है

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

क्यूं कर? इसे multiline 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)

आपकी मूल फ़ाइल दोहराएगा।


सार्वभौमिक_नलाइन को सत्य पर सेट करें, यानी

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

हाल ही में एक उपयोगकर्ता ने पूछा कि @Aaron Maenpaa का जवाब बस काम करता है

क्या कोई और आसान तरीका है? 'fhand.read ()। डीकोड ("ASCII")' [...] यह बहुत लंबा है!

आप उपयोग कर सकते हैं

command_stdout.decode()

decode() एक मानक तर्क है

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


http://docs.python.org/3/library/sys.html ,

मानक धाराओं से / से बाइनरी डेटा लिखने या पढ़ने के लिए, अंतर्निहित बाइनरी बफर का उपयोग करें। उदाहरण के लिए, बाइट्स को stdout पर लिखने के लिए, sys.stdout.buffer.write (b'abc ') का उपयोग करें।





python-3.x