[python] Python에서 stdout을 파이핑 할 때 올바른 인코딩 설정

파이썬 프로그램의 출력을 파이핑 할 때, 파이썬 인터프리터는 인코딩에 대해 혼란스러워서 None으로 설정합니다. 이것은 다음과 같은 프로그램을 의미합니다 :

# -*- coding: utf-8 -*-
print u"åäö"

정상적으로 실행되면 정상적으로 작동하지만 다음과 같이 실패합니다.

UnicodeEncodeError : ‘ascii’코덱은 위치 0에서 문자 u ‘\ xa0’을 인코딩 할 수 없습니다. 서 수가 범위 내에 있지 않습니다 (128)

파이프 시퀀스에서 사용될 때.

배관 할 때이 작업을 수행하는 가장 좋은 방법은 무엇입니까? 쉘 / 파일 시스템 / 사용중인 인코딩을 무엇이든 사용하도록 지시 할 수 있습니까?

지금까지 내가 본 제안은 site.py를 직접 수정 하거나이 핵을 사용하여 기본 인코딩을 하드 코딩하는 것입니다.

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

배관 작업을하는 더 좋은 방법이 있습니까?



답변

파이썬은 터미널 응용 프로그램이 사용하는 인코딩으로 출력을 인코딩하기 때문에 스크립트에서 실행될 때 코드가 작동합니다. 배관하는 경우 직접 인코딩해야합니다.

일반적으로 내부적으로 항상 유니 코드를 사용하십시오. 수신 한 내용을 디코딩하고 전송 한 내용을 인코딩하십시오.

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

또 다른 교훈적인 예는 ISO-8859-1과 UTF-8 사이를 변환하여 모든 것을 대문자로 만드는 Python 프로그램입니다.

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

사용하는 일부 모듈과 라이브러리는 그것이 ASCII라는 사실에 의존 할 수 있기 때문에 시스템 기본 인코딩을 설정하는 것은 좋지 않습니다. 하지마


답변

먼저이 솔루션에 대해 :

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

매번 주어진 인코딩으로 명시 적으로 인쇄하는 것은 실용적이지 않습니다. 반복적이고 오류가 발생하기 쉽습니다.

더 나은 솔루션은 sys.stdout프로그램 시작시 변경 하여 선택한 인코딩으로 인코딩하는 것입니다. 다음은 Python 에서 찾은 솔루션 중 하나 입니다. sys.stdout.encoding은 어떻게 선택됩니까? , 특히 “toka”의 주석 :

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)


답변

환경 변수 “PYTHONIOENCODING”을 “utf_8″로 변경하려고 할 수 있습니다. 나는 이 문제에 관한 나의 시련에 관한 페이지를 썼다 .

블로그 게시물의 Tl; dr :

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))

당신을 제공합니다

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻


답변

export PYTHONIOENCODING=utf-8

일을하지만 파이썬 자체에서 설정할 수는 없습니다 …

우리가 할 수있는 일은 설정되어 있지 않은지 확인하고 사용자에게 다음을 사용하여 호출 스크립트 전에 설정하도록 지시하는 것입니다.

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)

주석에 응답하도록 업데이트하십시오. stdout으로 파이핑 할 때 문제가 발생했습니다. Fedora 25 Python 2.7.13에서 테스트했습니다.

python --version
Python 2.7.13

고양이 b.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys

print sys.stdout.encoding

./b.py 실행 중

UTF-8

./b.py 실행 중 | 적게

None


답변

지난주 비슷한 문제 가있었습니다 . 내 IDE (PyCharm)에서 쉽게 고칠 수있었습니다.

여기 내 수정이 있었다 :

PyCharm 메뉴 표시 줄에서 시작 : 파일-> 설정 …-> 편집기-> 파일 인코딩 다음 “IDE 인코딩”, “프로젝트 인코딩”및 “속성 파일의 기본 인코딩”을 모두 UTF-8로 설정하면 이제 작동합니다. 매력처럼.

도움이 되었기를 바랍니다!


답변

크레이그 맥퀸의 대답은 위생적인 ​​버전입니다.

import sys, codecs
class EncodedOut:
    def __init__(self, enc):
        self.enc = enc
        self.stdout = sys.stdout
    def __enter__(self):
        if sys.stdout.encoding is None:
            w = codecs.getwriter(self.enc)
            sys.stdout = w(sys.stdout)
    def __exit__(self, exc_ty, exc_val, tb):
        sys.stdout = self.stdout

용법:

with EncodedOut('utf-8'):
    print u'ÅÄÖåäö'


답변

나는 다음과 같은 호출로 “자동화”할 수 있었다.

def __fix_io_encoding(last_resort_default='UTF-8'):
  import sys
  if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
      import os
      defEnc = None
      if defEnc is None :
        try:
          import locale
          defEnc = locale.getpreferredencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.getfilesystemencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.stdin.encoding
        except: pass
      if defEnc is None :
        defEnc = last_resort_default
      os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
      os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding

예,이 “setenv”가 실패하면 무한 루프를 얻을 수 있습니다.