Programing

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

lottogame 2020. 3. 6. 08:15
반응형

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"가 실패하면 무한 루프를 얻을 수 있습니다.


나는 여기서 무슨 일이 일어나고 있는지 깨닫기 전에 오랜 시간 동안 실험해야했던 것을 언급 할 것이라고 생각했습니다. 이것은 여기에있는 모든 사람들에게 너무나 명백하여 언급하지 않았습니다. 그러나 그들이 그 원칙을 가지고 있다면 나에게 도움이 될 것입니다 ...!

NB : Jython을 특별히 v 2.7로 사용하고 있으므로 CPython에 적용되지 않을 수도 있습니다 ...

NB2 : 내 .py 파일의 첫 두 줄은 다음과 같습니다.

# -*- coding: utf-8 -*-
from __future__ import print_function

"%"(일명 "보간 연산자") 문자열 구성 메커니즘으로 인해 추가 문제가 발생합니다. "환경"의 기본 인코딩이 ASCII이고 다음과 같은 작업을 시도하면

print( "bonjour, %s" % "fréd" )  # Call this "print A"

Eclipse에서 실행하는 데 어려움이 없습니다 ... Windows CLI (DOS 창)에서 인코딩이 코드 페이지 850 (내 Windows 7 OS) 또는 이와 유사한 것으로 유럽 최소한의 악센트 문자를 처리 할 수 ​​있다는 것을 알 수 있습니다. 작동합니다.

print( u"bonjour, %s" % "fréd" ) # Call this "print B"

작동합니다.

OTOH가 CLI에서 파일로 직접 전송하는 경우 stdout 인코딩은 None이며 기본적으로 ASCII로 설정됩니다 (어쨌든 내 OS에서) 위의 인쇄 중 하나를 처리 할 수 ​​없습니다 ... (두려운 인코딩 오류).

따라서 stdout을 다음과 같이 사용하여 리디렉션 할 수 있습니다.

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

CLI 파이프에서 파일로 실행 해보십시오 ... 매우 이상하게도 위의 인쇄 A는 작동하지만 위의 인쇄 B는 인코딩 오류를 발생시킵니다! 그러나 다음은 정상적으로 작동합니다.

print( u"bonjour, " + "fréd" ) # Call this "print C"

나는 (가짜)에 온 결론은 지정된 문자열이 될 경우이다 유니 코드 은 "U"접두어를 사용하여 문자열을 그 기본 환경 인코딩의 사용을 포함 나타나는 % -handling 메커니즘에 제출 에 관계없이 stdout을 리디렉션하도록 설정했는지 여부

사람들이 이것을 다루는 방법은 선택의 문제입니다. 유니 코드 전문가 가이 문제가 발생하는 이유, 내가 어떤 식으로 잘못했는지 여부, 선호되는 솔루션, CPython 에도 적용 되는지 여부, 파이썬 3에서 발생하는지 등 을 말할 것을 환영합니다 .


Ubuntu 12.10 및 그놈 터미널에서는 프로그램이 표준 출력으로 인쇄되거나 다른 프로그램의 파이프에 연결될 때 오류가 발생하지 않습니다. 파일 인코딩과 터미널 인코딩은 모두 UTF-8 입니다.

$ cat a.py
# -*- coding: utf-8 -*-
print "åäö"
$ python a.py
åäö
$ python a.py | tee out
åäö

어떤 OS 및 터미널 에뮬레이터를 사용하고 있습니까? iTerm 2 와 OS X를 사용할 때 일부 동료들도 비슷한 문제가 있다고 들었습니다 . iTerm 2가 범인 일 수 있습니다.

업데이트 :이 답변이 잘못되었습니다-자세한 내용은 의견을 참조하십시오


레거시 응용 프로그램에서이 문제가 발생하여 인쇄 된 위치를 식별하기가 어려웠습니다. 나는이 해킹으로 나를 도왔다 :

# encoding_utf8.py
import codecs
import builtins


def print_utf8(text, **kwargs):
    print(str(text).encode('utf-8'), **kwargs)


def print_utf8(fn):
    def print_fn(*args, **kwargs):
        return fn(str(*args).encode('utf-8'), **kwargs)
    return print_fn


builtins.print = print_utf8(print)

내 스크립트 위에 test.py :

import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)

그러면 인코딩을 사용하기 위해 인쇄 할 모든 호출이 변경되므로 콘솔에서 다음을 인쇄합니다.

$ python test.py
b'Axwell \xce\x9b Ingrosso'

참고 URL : https://stackoverflow.com/questions/492483/setting-the-correct-encoding-when-piping-stdout-in-python



반응형