[python] 바이트를 문자열로 변환

이 코드를 사용하여 외부 프로그램에서 표준 출력을 얻습니다.

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

communi () 메소드는 바이트 배열을 리턴합니다.

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

바이트 값을 다시 문자열로 어떻게 변환합니까? “배터리”를 수동으로 사용하는 대신 사용하는 것입니다. 그리고 파이썬 3에서도 괜찮기를 바랍니다.



답변

문자열을 생성하려면 bytes 객체를 디코딩해야합니다.

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


답변

바이트 문자열을 디코딩하여 문자 (유니 코드) 문자열로 바꿔야합니다.

파이썬 2에서

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

또는

unicode('hello', encoding)

파이썬 3에서

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

또는

str(b'hello', encoding)


답변

나는이 방법이 쉽다고 생각한다.

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


답변

인코딩을 모르는 경우 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]성능과 안정성을 모두 검증 하려면 변환 테스트가 필요합니다 .

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

자세한 내용은 Python의 유니 코드 지원 을 참조하십시오.

업데이트 20170119 : 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'))


답변

Python 3 에서 기본 인코딩은입니다 "utf-8". 직접 사용할 수 있습니다.

b'hello'.decode()

어느 것이

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

반면 에 Python 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')

아론의 대답은 당신 사용 인코딩. 그리고 Windows는 ‘windows-1252’를 사용한다고 생각합니다. 콘텐츠에 비정상적인 (ASCII 이외의) 문자가있는 경우에만 문제가되지만 차이가 있습니다.

그런데,이 사실 않습니다 문제는 이유는 파이썬 바이너리와 텍스트 데이터에 대한 서로 다른 두 가지 유형을 사용하여 이동한다는 것입니다 : 당신이 그것을 말하지 않는 한 인코딩을 모르고 있기 때문에, 그들 사이에 마술 변환 할 수 없습니다! 아는 유일한 방법은 Windows 설명서를 읽거나 여기를 읽는 것입니다.


답변

universal_newlines를 True로 설정하십시오.

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