पायथन में स्टडआउट करते समय सही एन्कोडिंग सेट करना


343

पायथन प्रोग्राम के आउटपुट को पाइप करते समय, पायथन दुभाषिया एन्कोडिंग के बारे में भ्रमित हो जाता है और इसे किसी पर सेट नहीं करता है। इसका मतलब इस तरह से एक कार्यक्रम है:

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

सामान्य रूप से चलने पर ठीक काम करेगा, लेकिन इसके साथ विफल:

यूनिकोडेनाकोड: 'एससीआई' कोडक चरित्र u '\ xa0 को स्थिति 0 में सांकेतिक शब्दों में बदलना नहीं कर सकता है: क्रम में नहीं (128)

जब एक पाइप अनुक्रम में उपयोग किया जाता है।

पाइपिंग करते समय यह काम करने का सबसे अच्छा तरीका क्या है? क्या मैं इसे केवल शेल / फाइलसिस्टम एन्कोडिंग का उपयोग करने के लिए कह सकता हूं / जो कुछ भी उपयोग कर रहा है?

इस प्रकार अब तक मैंने जो सुझाव देखे हैं, वे सीधे आपके साइट-थ्रू को संशोधित करना है, या इस हैक का उपयोग करके डिफॉल्टेंकोडिंग को हार्डकोड करना है:

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

क्या पाइपिंग का काम करने का एक बेहतर तरीका है?


1
यह भी देखें stackoverflow.com/questions/4545661/…
ShreevatsaR

2
यदि आपको विंडोज़ पर यह समस्या है, तो आप chcp 65001अपनी स्क्रिप्ट निष्पादित करने से पहले भी चला सकते हैं । इसके मुद्दे हो सकते हैं, लेकिन यह अक्सर मदद करता है, और इसके लिए बहुत अधिक टाइपिंग (कम से कम set PYTHONIOENCODING=utf_8) की आवश्यकता नहीं होती है ।
टॉमस गैंडर

chcp कमांड PYTHONIOENCODING सेट करने के समान नहीं है। मुझे लगता है कि chcp सिर्फ टर्मिनल के लिए ही कॉन्फ़िगरेशन है और इसका फाइल में लिखने से कोई लेना-देना नहीं है (जो कि जब आप स्टडआउट कर रहे हैं तो आप क्या कर रहे हैं)। setx PYTHONENCODING utf-8यदि आप टाइपिंग को सहेजना चाहते हैं, तो इसे स्थायी बनाने का प्रयास करें।
ejm


मैंने कुछ हद तक संबंधित मुद्दे का सामना किया, और यहां एक समाधान मिला -> stackoverflow.com/questions/48782529/…
bkrishna2006

जवाबों:


162

स्क्रिप्ट में चलने पर आपका कोड काम करता है क्योंकि पायथन आउटपुट को जो कुछ भी आपके टर्मिनल एप्लिकेशन का उपयोग कर एन्कोडिंग करता है, को एन्कोड करता है। यदि आप पाइपिंग कर रहे हैं तो आपको इसे स्वयं एनकोड करना होगा।

अंगूठे का एक नियम है: हमेशा यूनिकोड का आंतरिक रूप से उपयोग करें। डिकोड करें जो आप प्राप्त करते हैं, और जो आप भेजते हैं उसे सांकेतिक शब्दों में बदलना।

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

एक और उपदेशात्मक उदाहरण ISO-8859-1 और UTF-8 के बीच परिवर्तित करने के लिए एक पायथन प्रोग्राम है, जो बीच में सब कुछ बड़ा बनाता है।

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 है। यह मत करो।


11
समस्या यह है कि उपयोगकर्ता एन्कोडिंग को स्पष्ट रूप से निर्दिष्ट नहीं करना चाहता है। वह सिर्फ IO के लिए यूनिकोड का उपयोग करना चाहता है। और जो एन्कोडिंग वह उपयोग करता है वह स्थानीय सेटिंग में निर्दिष्ट एन्कोडिंग होना चाहिए, टर्मिनल एप्लिकेशन सेटिंग्स में नहीं। AFAIK, पायथन 3 इस मामले में एक स्थानीय एन्कोडिंग का उपयोग करता है । परिवर्तन sys.stdoutअधिक सुखद तरीका लगता है।
एंड्री वाल्स्सोविच शेख

4
एन्कोडिंग / डिकोडिंग प्रत्येक स्ट्रिंग को उत्कट रूप से बग का कारण बनता है जब एक सांकेतिक शब्दों में बदलना या डिकोड गायब है या एक बार कहीं और जोड़ा जाता है। आउटपुट एन्कोडिंग सेट किया जा सकता है जब आउटपुट एक टर्मिनल होता है, तो यह तब सेट किया जा सकता है जब आउटपुट टर्मिनल नहीं होता है। इसे निर्दिष्ट करने के लिए एक मानक LC_CTYPE वातावरण भी है। यह अजगर में है लेकिन यह इसका सम्मान नहीं करता है।
रासमस काज

65
यह उत्तर गलत है। आपको अपने प्रोग्राम के प्रत्येक इनपुट और आउटपुट पर मैन्युअल रूप से परिवर्तित नहीं होना चाहिए ; यह भंगुर और पूरी तरह से अस्वीकार्य है।
ग्लेन मेनार्ड

29
@ ग्लेन मेनार्ड: तो क्या IYO सही जवाब है? It's यह उत्तर गलत है ’
smci

14
@smci: इसका जवाब आपके स्क्रिप्ट को संशोधित नहीं है, सेट किया गया है PYTHONIOENCODINGअगर तुम अजगर 2 में स्क्रिप्ट के stdout रीडायरेक्ट कर रहे हैं
JFS

168

सबसे पहले, इस समाधान के बारे में:

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

हर बार दिए गए एन्कोडिंग के साथ स्पष्ट रूप से प्रिंट करना व्यावहारिक नहीं है। यह दोहराव और त्रुटि-प्रवण होगा।

एक बेहतर समाधान यह है sys.stdoutकि आप अपने प्रोग्राम की शुरुआत में, एक चुने हुए एन्कोडिंग के साथ एनकोड करें। यहाँ एक उपाय है जो मैंने पायथन पर पाया है: sys.stdout.encoding कैसे चुना जाता है? , विशेष रूप से "टोका" द्वारा एक टिप्पणी:

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

7
दुर्भाग्य से, केवल यूनिकोड को स्वीकार करने के लिए sys.stdout बदलने से बहुत सी लाइब्रेरीज़ टूट जाती हैं, जो यह उम्मीद करती हैं कि यह एन्कोडेड बायरस्ट्रेस को स्वीकार करेगी।
नोसकोलो

6
nosklo: तो जब उत्पादन एक टर्मिनल है तो यह मज़बूती से और स्वचालित रूप से कैसे काम कर सकता है?
रासमस काज

3
@ रासमस काज: बस अपने यूनिकोड प्रिंटिंग फंक्शन को परिभाषित करें और हर बार यूनिकोड प्रिंट करने के लिए इसका उपयोग करें: def myprint(unicodeobj): print unicodeobj.encode('utf-8')- आप स्वचालित रूप से निरीक्षण करके टर्मिनल एन्कोडिंग का पता लगाते हैं sys.stdout.encoding, लेकिन आपको उस मामले पर विचार करना चाहिए जहां यह है None(यानी जब फ़ाइल पर आउटपुट पुनर्निर्देशित किया जाता है) तो आपको वैसे भी एक अलग फ़ंक्शन की आवश्यकता है।
nosklo

3
@ नोस्कोलो: यह sys.stdout को केवल यूनिकोड स्वीकार नहीं करता है। आप एक स्ट्रीमव्यूटर के लिए str और यूनिकोड दोनों पास कर सकते हैं।
ग्लेन मेनार्ड

9
मुझे लगता है कि यह जवाब python2 के लिए इरादा था। इस कोड के साथ सावधान रहें जो python2 और python3 दोनों का समर्थन करने का इरादा है । मेरे लिए यह सामान तोड़ रहा है जब python3 के तहत भाग गया।
16:15

130

आप पर्यावरण चर "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
ö ☺ ☻

2
बदलते sys.stdout.encoding शायद काम नहीं करता है, लेकिन sys.stdout बदलना काम करता है sys.stdout = codecs.getwriter(encoding)(sys.stdout):। यह अजगर कार्यक्रम के भीतर से किया जा सकता है, इसलिए उपयोगकर्ता को एनवी चर सेट करने के लिए मजबूर नहीं किया जाता है।
ब्लू फ़ॉस्ट

7
@ jeckyll2hide: PYTHONIOENCODINGकाम करता है। बाइट्स की व्याख्या कैसे की जाती है क्योंकि एक पाठ उपयोगकर्ता पर्यावरण द्वारा परिभाषित किया गया है। आपकी स्क्रिप्ट को यह मानकर नहीं चलना चाहिए कि उपयोगकर्ता परिवेश को किस वर्ण एन्कोडिंग का उपयोग करना चाहिए। यदि पायथन स्वचालित रूप से सेटिंग्स नहीं उठाता है तो PYTHONIOENCODINGआपकी स्क्रिप्ट के लिए सेट किया जा सकता है। जब तक आउटपुट फ़ाइल / पाइप पर पुनर्निर्देशित नहीं हो जाता है तब तक आपको इसकी आवश्यकता नहीं होनी चाहिए।
JFS

8
+1। ईमानदारी से मुझे लगता है कि यह एक पायथन बग है। जब मैं आउटपुट रीडायरेक्ट करता हूं तो मैं वही बाइट्स चाहता हूं जो टर्मिनल पर होगी, लेकिन एक फाइल में। शायद यह सभी के लिए नहीं है, लेकिन यह एक अच्छा डिफ़ॉल्ट है। एक तुच्छ ऑपरेशन पर कोई स्पष्टीकरण के साथ कड़ी मेहनत करना जो आमतौर पर "बस काम करता है" एक खराब डिफ़ॉल्ट है।
संक १

@ सनक: मैं एकमात्र तरीका यह बता सकता हूं कि पायथन के कार्यान्वयन जानबूझकर एक लोहे की लट को लागू करने और स्टार्टअप समय में स्टडआउट पर एन्कोडिंग का स्थायी विकल्प क्यों लागू होगा, ताकि बाद में आने वाले किसी भी बुरी तरह से एन्कोडेड सामान को रोकने के लिए हो सकता है। या इसे बदलना केवल एक अनिमित सुविधा है, इस स्थिति में उपयोगकर्ता इसे बाद में बदलने की अनुमति देता है जो एक उचित पायथन सुविधा अनुरोध होगा।
daveagp

2
@daveagp मेरा कहना है, मेरे कार्यक्रम का व्यवहार इस बात पर निर्भर नहीं होना चाहिए कि क्या यह पुनर्निर्देशित है या नहीं --- जब तक मैं वास्तव में यह नहीं चाहता, जिस स्थिति में मैं इसे स्वयं लागू करता हूं। पायथन किसी अन्य कंसोल टूल के साथ मेरे अनुभव के विपरीत व्यवहार करता है। यह कम से कम आश्चर्यजनक सिद्धांत का उल्लंघन करता है। मैं इसे एक डिजाइन दोष मानता हूं जब तक कि बहुत मजबूत तर्क न हो।
संक देव १४'१५ को

62
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 में पाइपिंग की जाती है। मैंने फेडोरा 25 पायथन 2.7.13 में परीक्षण किया

python --version
Python 2.7.13

बिल्ली

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

print sys.stdout.encoding

चल रहा है ।/b.py

UTF-8

चल रहा है ।/b.py | कम से

None

2
वह चेक पाइथन 2.7.13 में काम नहीं करता है। sys.stdout.encodingस्वचालित रूप से LC_CTYPEस्थानीय मान के आधार पर सेट किया जाता है ।
एम्फ़ैटेमाचिन

1
mail.python.org/pipermail/python-list/2011-June/605938.html उदाहरण वहाँ अभी भी काम करते हैं, यानी जब आप ./a.py> out.txt sys.stdout.encoding है कोई नहीं का उपयोग
सर्जियो

Backblaze B2 से सिंक स्क्रिप्ट और निर्यात PYTHONIOENCODING = utf-8 से मुझे एक समान समस्या थी। डेबियन स्ट्रेच पर पायथन 2.7।
0x3333

5

मेरे पास पिछले सप्ताह इसी तरह का मुद्दा था । मेरी IDE (PyCharm) को ठीक करना आसान था।

यहाँ मेरा फिक्स था:

PyCharm मेनू बार से शुरू: फ़ाइल -> सेटिंग ... -> संपादक -> फ़ाइल एन्कोडिंग, फिर सेट करें: "IDE एन्कोडिंग", "प्रोजेक्ट एन्कोडिंग" और "गुणों के लिए डिफ़ॉल्ट एन्कोडिंग" सभी के लिए UTF-8 फाइल और वह अब काम करता है जादू की तरह।

उम्मीद है की यह मदद करेगा!


4

क्रेग मैकक्वीन के उत्तर का एक तर्कपूर्ण सैनिटाइज़्ड संस्करण।

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'ÅÄÖåäö'

2

मैं इसे एक कॉल के साथ "स्वचालित" कर सकता था:

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

हां, यदि यह "सेटेनव" विफल रहता है, तो यहां एक अनंत लूप प्राप्त करना संभव है।


1
दिलचस्प है, लेकिन एक पाइप इस बारे में खुश नहीं लगता है
n611x007

2

मैंने सोचा था कि मैं यहां कुछ का उल्लेख करूंगा, जिसे मुझे प्रयोग करने से पहले एक लंबा समय बिताना पड़ा था। यह यहाँ हर किसी के लिए इतना स्पष्ट हो सकता है कि उन्होंने इसका उल्लेख करने की जहमत नहीं उठाई। लेकिन यह मेरी मदद की है अगर वे था, तो उस सिद्धांत पर ...!

एनबी: मैं उपयोग कर रहा हूँ Jython विशेष रूप से, वी 2.7, तो बस संभवतः इस पर लागू नहीं हो CPython ...

NB2: मेरी .py फ़ाइल की पहली दो पंक्तियाँ यहाँ हैं:

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

"%" (AKA "इंटरपोलेशन ऑपरेटर") स्ट्रिंग कंस्ट्रक्शन मैकेनिज्म ADDITIONAL समस्याओं का कारण बनता है ... यदि "पर्यावरण" का डिफ़ॉल्ट एन्कोडिंग ASCII है और आप कुछ ऐसा करने की कोशिश करते हैं

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

आपको ग्रहण में चलने में कोई कठिनाई नहीं होगी ... विंडोज सीएलआई (डॉस विंडो) में आप पाएंगे कि एन्कोडिंग कोड पृष्ठ 850 (मेरा विंडोज 7 ओएस) या कुछ इसी तरह का है, जो कम से कम यूरोपीय उच्चारण पात्रों को संभाल सकता है, इसलिए यह 'काम करेंगे।

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

काम भी करेगा।

यदि, OTOH, आप सीएलआई से एक फ़ाइल को निर्देशित करते हैं, तो स्टडआउट एन्कोडिंग कोई भी नहीं होगा, जो कि ASCII (वैसे भी मेरे ओएस पर) के लिए डिफ़ॉल्ट होगा, जो उपरोक्त प्रिंटों में से किसी को भी संभालने में सक्षम नहीं होगा ... (भयानक एन्कोडिंग त्रुटि)।

तो फिर आप का उपयोग करके अपने stdout पुनर्निर्देशित करने के बारे में सोच सकते हैं

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

और एक फ़ाइल को सीएलआई पाइपिंग में चलाने की कोशिश करें ... बहुत अजीब तरह से, ऊपर एक प्रिंट काम करेगा ... लेकिन ऊपर बी प्रिंट एन्कोडिंग त्रुटि को फेंक देगा! निम्नलिखित हालांकि ठीक काम करेगा:

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

मैं (अनंतिम रूप से) यह निष्कर्ष निकालता हूं कि यदि एक स्ट्रिंग जो "यू" उपसर्ग का उपयोग करते हुए एक यूनिकोड स्ट्रिंग के रूप में निर्दिष्ट है, तो% -हैंडलिंग तंत्र के लिए प्रस्तुत की जाती है, जिसमें डिफ़ॉल्ट पर्यावरण एन्कोडिंग का उपयोग शामिल है, भले ही वह क्यों न हो क्या आपने रीडायरेक्ट करने के लिए स्टडआउट सेट किया है!

लोग इससे कैसे निपटते हैं यह पसंद का मामला है। मैं यूनिकोड विशेषज्ञ का स्वागत करने के लिए कहूंगा कि ऐसा क्यों होता है, क्या मुझे यह किसी तरह से गलत लगा है, इसका पसंदीदा समाधान क्या है, क्या यह सीपीथॉन पर भी लागू होता है , चाहे वह पायथन 3 में होता है, आदि, आदि।


यह अजीब नहीं है, ऐसा इसलिए "fréd"है क्योंकि एक बाइट अनुक्रम है और एक यूनिकोड स्ट्रिंग नहीं है, इसलिए codecs.getwriterआवरण इसे अकेला छोड़ देगा। आपको एक अग्रणी की आवश्यकता है u, या from __future__ import unicode_literals
मथायस उरलिच

@MatthiasUrlichs ठीक है ... धन्यवाद ... लेकिन मैं सिर्फ आईटी के सबसे अधिक उल्लंघन वाले पहलुओं में से एक को कूटता हूं। आप अपनी समझ कहाँ से प्राप्त करते हैं? उदाहरण के लिए, मैंने अभी एक और प्रश्न यहाँ एन्कोडिंग के बारे में पोस्ट किया है: stackoverflow.com/questions/44483067/… : यह Java, Eclipse, Cygwin & Gradle के बारे में है। अगर आपकी विशेषज्ञता इससे दूर हो जाती है, तो कृपया मदद करें ... सबसे ऊपर मैं जानना चाहता हूं कि अधिक जानकारी कहां है!
माइक कृंतक

1

मैं इस समस्या में एक विरासत आवेदन में भाग गया, और यह पहचानना मुश्किल था कि क्या छपा है। मैंने खुद को इस हैक के साथ मदद की:

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

1

विंडोज पर, मुझे एक संपादक (जैसे उदात्त पाठ) से पायथन कोड चलाते समय बहुत बार यह समस्या थी, लेकिन कमांड-लाइन से इसे चलाने पर नहीं

इस मामले में, अपने संपादक के मापदंडों की जाँच करें। SublimeText के मामले में, इसने Python.sublime-buildइसे हल किया:

{
  "cmd": ["python", "-u", "$file"],
  "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
  "selector": "source.python",
  "encoding": "utf8",
  "env": {"PYTHONIOENCODING": "utf-8", "LANG": "en_US.UTF-8"}
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.