แปลงไบต์เป็นสตริง


2307

ฉันใช้รหัสนี้เพื่อรับเอาต์พุตมาตรฐานจากโปรแกรมภายนอก:

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

อย่างไรก็ตามฉันต้องการทำงานกับผลลัพธ์เป็นสตริง Python ปกติ เพื่อให้ฉันสามารถพิมพ์ได้เช่นนี้

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


47
ทำไมไม่str(text_bytes)ทำงาน นี่มันแปลกประหลาดสำหรับฉัน
Charlie Parker

13
@CharlieParker เพราะstr(text_bytes)ไม่สามารถระบุการเข้ารหัสได้ ทั้งนี้ขึ้นอยู่กับสิ่งที่อยู่ใน text_bytes, text_bytes.decode('cp1250) text_bytes.decode('utf-8')`อาจส่งผลสตริงที่แตกต่างกันมากที่จะ
เครกแอนเดอร์สัน

6
ดังนั้นstrฟังก์ชั่นจะไม่แปลงเป็นสตริงจริงอีกต่อไป มีหนึ่งที่จะพูดการเข้ารหัสอย่างชัดเจนด้วยเหตุผลบางอย่างฉันขี้เกียจอ่านทำไม เพียงแปลงเป็นutf-8และดูว่ารหัส ur ใช้งานได้หรือไม่ เช่นvar = var.decode('utf-8')
Charlie Parker

1
@CraigAnderson: unicode_text = str(bytestring, character_encoding)ทำงานได้ตามที่คาดไว้ใน Python 3 แม้ว่าunicode_text = bytestring.decode(character_encoding)จะดีกว่าเพื่อหลีกเลี่ยงความสับสนกับการstr(bytes_obj)สร้างข้อความแทนbytes_objแทนที่จะถอดรหัสเป็นข้อความ: str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'และstr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
jfs

คำตอบ:


3674

คุณต้องถอดรหัสวัตถุไบต์เพื่อสร้างสตริง:

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

58
การใช้"windows-1252"ไม่น่าเชื่อถือ (เช่นสำหรับ Windows รุ่นภาษาอื่น) จะใช้งานได้ดีที่สุดsys.stdout.encodingหรือไม่?
nikow

12
บางทีนี่อาจช่วยให้ใครบางคนเพิ่มเติม: บางครั้งคุณใช้ไบต์อาร์เรย์สำหรับการสื่อสาร TCP อดีต หากคุณต้องการแปลงอาร์เรย์ไบต์เป็นสตริงการตัดอักขระ '\ x00' ต่อท้ายคำตอบต่อไปนี้ไม่เพียงพอ ใช้ b'example \ x00 \ x00'.decode ('utf-8'). strip ('\ x00') จากนั้น
Wookie88

2
ฉันได้กรอกข้อผิดพลาดเกี่ยวกับการบันทึกไว้ที่bugs.python.org/issue17860 - อย่าลังเลที่จะเสนอแพทช์ ถ้ามันยากที่จะมีส่วนร่วม - แสดงความคิดเห็นวิธีการปรับปรุงที่ยินดีต้อนรับ
Anatoly techtonik

44
ในหลาม 2.7.6 ไม่ได้จัดการ->b"\x80\x02\x03".decode("utf-8") UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
martineau

9
หากเนื้อหาเป็นค่าไบนารีแบบสุ่มการutf-8แปลงมีแนวโน้มที่จะล้มเหลว แทนที่จะดูคำตอบ @techtonik (ด้านล่าง) stackoverflow.com/a/27527728/198536
wallyk

215

คุณต้องถอดรหัสสตริงไบต์และเปลี่ยนเป็นสตริงอักขระ (Unicode)

บน Python 2

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

หรือ

unicode('hello', encoding)

บน Python 3

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

หรือ

str(b'hello', encoding)

2
บน Python 3 จะเกิดอะไรขึ้นถ้าสตริงอยู่ในตัวแปร
Alaa M.

1
@AlaaM .: แบบเดียวกัน หากคุณมีvariable = b'hello'แล้วunicode_text = variable.decode(character_encoding)
JFS

182

ฉันคิดว่าวิธีนี้ง่าย:

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

6
ขอบคุณวิธีการของคุณใช้ได้กับฉันเมื่อไม่มีใครทำ ฉันมีอาร์เรย์ไบต์ที่ไม่ได้เข้ารหัสซึ่งฉันต้องการเปลี่ยนเป็นสตริง พยายามหาวิธีเข้ารหัสอีกครั้งเพื่อให้ฉันสามารถถอดรหัสเป็นสตริงได้ วิธีนี้ใช้ได้ผลอย่างสมบูรณ์แบบ!
leetNightshade

5
@leetNightshade: แต่มันไม่มีประสิทธิภาพมากนัก หากคุณมีอาร์เรย์ไบต์คุณจะต้องถอดรหัสเท่านั้น
Martijn Pieters

12
@Martijn Pieters ฉันเพิ่งทำเบนช์มาร์กง่ายๆกับคำตอบอื่น ๆ เหล่านี้โดยใช้การวิ่งมากกว่า 10,000 ครั้งstackoverflow.com/a/3646405/353094และวิธีการแก้ปัญหาข้างต้นนั้นเร็วขึ้นทุกครั้ง สำหรับ 10,000 รันใน Python 2.7.7 ใช้เวลา 8ms กับอื่น ๆ ที่ 12ms และ 18ms ได้รับอาจมีการเปลี่ยนแปลงบางอย่างขึ้นอยู่กับการป้อนข้อมูลรุ่นหลาม ฯลฯ ดูเหมือนจะไม่ช้าเกินไปสำหรับฉัน
leetNightshade

5
@Martijn Pieters ใช่ ดังนั้นเมื่อถึงตอนนี้นี่ไม่ใช่คำตอบที่ดีที่สุดสำหรับเนื้อหาของคำถามที่ถูกถาม และชื่อนั้นทำให้เข้าใจผิดใช่ไหม เขา / เธอต้องการแปลงสตริงไบต์เป็นสตริงปกติไม่ใช่อาร์เรย์ไบต์เป็นสตริง คำตอบนี้ใช้ได้สำหรับชื่อของคำถามที่ถาม
leetNightshade

5
สำหรับ python 3 ค่านี้ควรเทียบเท่ากับbytes([112, 52, 52])- btw bytes เป็นชื่อที่ไม่ดีสำหรับตัวแปรโลคอลอย่างแน่นอนเพราะเป็น p3 ในตัว
Mr_and_Mrs_D

92

หากคุณไม่รู้จักการเข้ารหัสดังนั้นหากต้องการอ่านไบนารีอินพุตลงในสตริงในวิธีที่เข้ากันได้กับ Python 3 และ Python 2 ให้ใช้การเข้ารหัสMS-DOS 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ที่ได้รับความนิยม (ค่าเริ่มต้น?) สำหรับงูหลาม 2 ดูจุดที่ขาดหายไปในเพจรหัสเค้าโครง - ordinal not in rangeมันเป็นที่ที่ฉายาหลามกับที่น่าอับอาย

UPDATE 20150604 : มีข่าวลือว่า Python 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'))

ดูการสนับสนุน Unicode ของ Pythonสำหรับรายละเอียด

UPDATE 20170119 : ฉันตัดสินใจที่จะใช้ slash escaping decode ที่ใช้ได้กับทั้ง Python 2 และ Python 3 มันควรจะช้ากว่าcp437โซลูชัน แต่มันควรให้ผลลัพธ์ที่เหมือนกันในทุกเวอร์ชันของ Python

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

6
ฉันรู้สึกเหมือนงูใหญ่ควรมีกลไกในการแทนที่สัญลักษณ์ที่หายไปและดำเนินการต่อ
Anatoly techtonik

@techtonik: วิธีนี้ใช้ไม่ได้กับอาเรย์ที่ทำงานใน python2
user2284570

@ user2284570 คุณหมายถึงรายการหรือไม่ และทำไมมันจึงควรใช้กับอาร์เรย์? โดยเฉพาะอย่างยิ่งอาร์เรย์ลอย ..
Anatoly techtonik

คุณสามารถละเว้นข้อผิดพลาด unicode ด้วยb'\x00\x01\xffsd'.decode('utf-8', 'ignore')ใน python 3
Antonis Kalou

3
@anatolytechtonik มีความเป็นไปได้ที่จะออกจากลำดับหนีในสตริงและย้ายไปคือจะส่งผลให้b'\x80abc'.decode("utf-8", "backslashreplace") '\\x80abc'ข้อมูลนี้นำมาจากหน้าเอกสารของยูนิโค้ดซึ่งดูเหมือนว่าจะได้รับการปรับปรุงตั้งแต่การเขียนคำตอบนี้
Nearoo

86

ใน Python 3การเข้ารหัสเริ่มต้นคือ"utf-8"เพื่อให้คุณสามารถใช้โดยตรง:

b'hello'.decode()

ซึ่งเทียบเท่ากับ

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

ในทางกลับกันใน Python 2 การเข้ารหัสค่าเริ่มต้นเป็นการเข้ารหัสสตริงเริ่มต้น ดังนั้นคุณควรใช้:

b'hello'.decode(encoding)

ที่encodingมีการเข้ารหัสที่คุณต้องการ

หมายเหตุ: เพิ่มการรองรับอาร์กิวเมนต์ของคำหลักใน Python 2.7


41

ฉันคิดว่าคุณต้องการสิ่งนี้จริง ๆ :

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

คำตอบของอาโรนได้ถูกต้องยกเว้นว่าคุณจำเป็นต้องรู้ที่การเข้ารหัสกับการใช้งาน และฉันเชื่อว่า Windows ใช้ 'windows-1252' จะสำคัญก็ต่อเมื่อคุณมีอักขระบางตัว (ไม่ใช่ ASCII) ที่ผิดปกติในเนื้อหาของคุณ แต่จากนั้นจะสร้างความแตกต่าง

โดยวิธีการที่เป็นจริงว่ามันไม่เรื่องคือเหตุผลที่งูใหญ่ย้ายไปใช้ทั้งสองประเภทที่แตกต่างกันสำหรับข้อมูลไบนารีและข้อความ: มันไม่สามารถแปลงได้อย่างน่าอัศจรรย์ระหว่างพวกเขาเพราะมันไม่ได้รู้ว่าการเข้ารหัสจนกว่าคุณจะบอกมัน! วิธีเดียวที่คุณจะรู้คืออ่านเอกสาร Windows (หรืออ่านได้ที่นี่)


3
open()ฟังก์ชั่นสำหรับการสตรีมข้อความหรือPopen()ถ้าคุณผ่านมันuniversal_newlines=Trueอย่างน่าอัศจรรย์ตัดสินใจเข้ารหัสตัวอักษรสำหรับคุณ ( locale.getpreferredencoding(False)ใน Python 3.3+)
jfs

2
'latin-1'เป็นการเข้ารหัสด้วยคำต่อคำที่มีการตั้งค่าจุดโค้ดทั้งหมดดังนั้นคุณสามารถใช้เพื่ออ่านสตริงไบต์ลงในสตริงใดก็ได้ที่ไพ ธ อนของคุณรองรับ
tripleee

@tripleee: 'latin-1'เป็นวิธีที่ดีในการรับ mojibake นอกจากนี้ยังมีการทดแทนเวทย์มนตร์บน Windows: มันเป็นเรื่องยากอย่างน่าประหลาดใจที่จะส่งข้อมูลจากกระบวนการหนึ่งไปยังอีกกระบวนการที่ไม่ได้แก้ไขเช่นdir: \xb6-> \x14(ตัวอย่างในตอนท้ายของคำตอบของฉัน)
jfs

32

ตั้งค่า universal_newlines เป็น True เช่น

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

5
ฉันใช้วิธีนี้และใช้งานได้ดี ถึงแม้ว่ามันเป็นเพียงการคาดเดาการเข้ารหัสตามความต้องการของผู้ใช้ในระบบของคุณดังนั้นมันจึงไม่แข็งแกร่งเท่ากับตัวเลือกอื่น ๆ นี่คือสิ่งที่มันทำอ้างอิง docs.python.org/3.4/library/subprocess.html: "ถ้า universal_newlines เป็น True, [stdin, stdout และ stderr] จะถูกเปิดเป็นสตรีมข้อความในโหมด newlines สากลโดยใช้การเข้ารหัสที่ส่งคืนโดย locale .getpreferredencoding (เท็จ)."
twasbrillig

เมื่อวันที่ 3.7คุณสามารถ (และควร) ทำแทนtext=True universal_newlines=True
บอริส

23

ในขณะที่คำตอบของ @Aaron Maenpaaใช้ได้ผลผู้ใช้เพิ่งถามว่า :

มีวิธีง่าย ๆ อีกไหม? 'fhand.read (). decode ("ASCII")' [... ] มันยาวมาก!

คุณสามารถใช้ได้:

command_stdout.decode()

decode()มีอาร์กิวเมนต์มาตรฐาน :

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


.decode()ที่ใช้'utf-8'อาจล้มเหลว (เอาต์พุตของคำสั่งอาจใช้การเข้ารหัสอักขระที่แตกต่างกันหรือส่งคืนลำดับไบต์ที่ไม่สามารถถอดรหัสได้) แม้ว่าอินพุตจะเป็น ascii (เซ็ตย่อยของ utf-8) ก็.decode()ใช้ได้
jfs

22

ในการตีความลำดับของไบต์เป็นข้อความคุณต้องรู้การเข้ารหัสอักขระที่เกี่ยวข้อง:

unicode_text = bytestring.decode(character_encoding)

ตัวอย่าง:

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

lsคำสั่งอาจสร้างผลลัพธ์ที่ไม่สามารถตีความได้ว่าเป็นข้อความ ชื่อไฟล์บน Unix อาจเป็นลำดับใด ๆ ของไบต์ยกเว้นเครื่องหมายทับb'/'และศูนย์ b'\0':

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

UnicodeDecodeErrorพยายามที่จะถอดรหัสซุปไบต์เช่นใช้ยกเข้ารหัส UTF-8

มันอาจจะแย่กว่านั้น การถอดรหัสอาจล้มเหลวอย่างเงียบ ๆ และสร้างmojibake หากคุณใช้การเข้ารหัสที่ไม่ถูกต้อง:

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

ข้อมูลเสียหาย แต่โปรแกรมของคุณยังไม่ทราบว่ามีความล้มเหลวเกิดขึ้น

โดยทั่วไปการเข้ารหัสอักขระที่จะใช้ไม่ได้ฝังอยู่ในลำดับไบต์ คุณต้องสื่อสารข้อมูลนี้นอกวง ผลลัพธ์บางรายการมีแนวโน้มมากกว่ารายการอื่นดังนั้นจึงchardetมีโมดูลที่สามารถเดาการเข้ารหัสอักขระได้ สคริปต์ Python เดียวอาจใช้การเข้ารหัสอักขระหลายตัวในที่ต่าง ๆ


lsเอาต์พุตสามารถแปลงเป็นสตริง Python โดยใช้os.fsdecode() ฟังก์ชั่นที่ประสบความสำเร็จแม้จะเป็นชื่อไฟล์ที่ไม่สามารถถอดรหัสได้ (มันใช้ sys.getfilesystemencoding()และsurrogateescapeจัดการข้อผิดพลาดบน Unix):

import os
import subprocess

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

os.fsencode()ที่จะได้รับไบต์เดิมคุณสามารถใช้

หากคุณผ่านuniversal_newlines=Trueพารามิเตอร์ให้subprocessใช้ locale.getpreferredencoding(False)เพื่อถอดรหัสไบต์เช่นสามารถอยู่ cp1252ใน Windows

เพื่อถอดรหัสกระแส byte on-the-fly, io.TextIOWrapper() สามารถนำมาใช้: ตัวอย่างเช่น

คำสั่งที่แตกต่างกันอาจใช้การเข้ารหัสอักขระที่แตกต่างกันสำหรับผลลัพธ์ของพวกเขาเช่นdirคำสั่งภายใน ( cmd) อาจใช้ cp437 ในการถอดรหัสเอาต์พุตคุณสามารถผ่านการเข้ารหัสอย่างชัดเจน (Python 3.6+):

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

ชื่อไฟล์อาจแตกต่างจากos.listdir()(ซึ่งใช้ Windows Unicode API) เช่น'\xb6'สามารถแทนที่ด้วย'\x14'แผนที่ตัวแปลงสัญญาณ cp437 ของ Python b'\x14'เพื่อควบคุมอักขระ U + 0014 แทน U + 00B6 (¶) ในการรองรับชื่อไฟล์ที่มีอักขระ Unicode โดยพลการดูที่ เอาต์พุต Decode PowerShell ที่มีอักขระ Unicode ที่ไม่ใช่ ASCII ในสตริง Python


16

เนื่องจากคำถามนี้ถามเกี่ยวกับsubprocessผลลัพธ์จริง ๆ แล้วคุณมีวิธีที่ตรงกว่านี้เนื่องจากPopenยอมรับคำหลักการเข้ารหัส (ใน Python 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é'

3
หรือด้วย Python 3.7 คุณสามารถส่งผ่านtext=Trueไปยังถอดรหัส stdin, stdout และ stderr โดยใช้การเข้ารหัสที่กำหนด (ถ้าตั้งค่า) หรือค่าเริ่มต้นของระบบเป็นอย่างอื่น Popen(['ls', '-l'], stdout=PIPE, text=True).
บอริส

การถอดรหัสlsเอาต์พุตโดยใช้การutf-8เข้ารหัสอาจล้มเหลว (ดูตัวอย่างในคำตอบของฉันจาก 2016 )
jfs

1
@ Boris: หากencodingมีการระบุtextพารามิเตอร์ดังนั้นพารามิเตอร์จะถูกละเว้น
jfs

11

หากคุณควรได้รับสิ่งต่อไปนี้โดยลองdecode():

AttributeError: วัตถุ 'str' ไม่มีแอตทริบิวต์ 'ถอดรหัส'

คุณยังสามารถระบุประเภทการเข้ารหัสได้โดยตรงในการส่ง:

>>> my_byte_str
b'Hello World'

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

6

เมื่อทำงานกับข้อมูลจากระบบ Windows (ที่มีการ\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งูหลามของฟังก์ชั่นข้อความที่อ่านตอนจบบรรทัดมักจะปกติดังนั้นสตริงที่ใช้เท่านั้น หากคุณได้รับข้อมูลไบนารีจากระบบ Windows Python จะไม่มีโอกาสทำเช่นนั้น ดังนั้น,

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

จะทำซ้ำไฟล์ต้นฉบับของคุณ


ฉันกำลังมองหา.replace("\r\n", "\n")นอกจากนี้มานาน นี่คือคำตอบหากคุณต้องการแสดง HTML อย่างถูกต้อง
mhlavacka

5

ฉันทำฟังก์ชันเพื่อล้างรายการ

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

6
จริงๆคุณสามารถโซ่ทั้งหมดของ.strip, .replace, .encodeฯลฯ โทรเข้าใจในรายการเดียวย้ำผ่านรายการครั้งเดียวแทน iterating มากกว่านั้นห้าครั้ง
เทย์เลอร์เอ็ดมิสตัน

1
@TaylorEdmiston บางทีมันอาจจะประหยัดในการจัดสรร แต่จำนวนของการดำเนินการจะยังคงเหมือนเดิม
JulienD

5

สำหรับ Python 3 วิธีนี้เป็นวิธีที่ปลอดภัยกว่าและPythonic ในการแปลงจากbyteเป็นstring:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): # Check if it's 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

5
1) ตามที่ @bodangly กล่าวว่าการตรวจสอบชนิดไม่ได้เป็น pythonic เลย 2) ฟังก์ชั่นที่คุณเขียนชื่อ " byte_to_str" ซึ่งบอกเป็นนัยว่ามันจะคืนค่า str แต่จะพิมพ์เฉพาะค่าที่แปลงแล้วและจะพิมพ์ข้อความแสดงข้อผิดพลาดหากล้มเหลว (แต่ไม่ยกข้อยกเว้น) วิธีการนี้ยังไม่เน้นเสียงและทำให้งงงวยbytes.decodeวิธีการแก้ปัญหาที่คุณให้
cosmicFluke

3

จากsys - พารามิเตอร์เฉพาะระบบและฟังก์ชั่น :

หากต้องการเขียนหรืออ่านข้อมูลไบนารีจาก / ไปยังสตรีมมาตรฐานให้ใช้บัฟเฟอร์ไบนารีพื้นฐาน ยกตัวอย่างเช่นการเขียนไบต์ที่ stdout sys.stdout.buffer.write(b'abc')ใช้


3
ไพพ์ไปยังกระบวนการย่อยนั้นเป็นบัฟเฟอร์ไบนารีอยู่แล้ว คำตอบของคุณไม่สามารถระบุวิธีรับค่าสตริงจากbytesค่าผลลัพธ์
Martijn Pieters

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

1
ในขณะที่รหัสนี้อาจตอบคำถามโดยให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ โปรดจำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่เพียงแค่คนที่ถามตอนนี้! โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้ นอกจากนี้ยังไม่เจ็บที่จะพูดถึงว่าทำไมคำตอบนี้จึงเหมาะสมกว่าคำอื่น ๆ
Dev-iL

คำอธิบายจะอยู่ในลำดับ
ปีเตอร์มอร์เทนเซ่น

1

สำหรับกรณีเฉพาะของคุณ"รันคำสั่งเชลล์และรับเอาต์พุตเป็นข้อความแทนที่จะเป็นไบต์" บน Python 3.7 คุณควรใช้subprocess.runและส่งต่อtext=True(เช่นเดียวกับcapture_output=Trueการจับเอาท์พุท)

command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout  # is a `str` containing your program's stdout

textเคยถูกเรียกใช้universal_newlinesและถูกเปลี่ยน (ดีเป็นนามแฝง) ใน Python 3.7 หากคุณต้องการสนับสนุนเวอร์ชัน Python ก่อน 3.7 ให้ส่งผ่านuniversal_newlines=Trueแทนtext=True


0

หากคุณต้องการแปลงไบต์ใด ๆ ไม่ใช่แค่การแปลงสตริงเป็นไบต์:

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

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

อย่างไรก็ตามมันไม่ได้มีประสิทธิภาพมาก จะเปลี่ยนรูปภาพ 2 MB เป็น 9 MB


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.