अजगर में त्रुटियों के बिना यूनिकोड को ASCII में बदलें


178

मेरा कोड सिर्फ एक वेब पेज को स्क्रैप करता है, फिर इसे यूनिकोड में बदल देता है।

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)

लेकिन मुझे एक UnicodeDecodeError:


Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/greg/clounce/main.py", line 55, in get
    html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

मुझे लगता है कि इसका मतलब है कि HTML में कहीं न कहीं यूनिकोड में कुछ गलत तरीके से गठित प्रयास शामिल हैं। क्या मैं त्रुटि प्राप्त करने के बजाय समस्या का कारण बनने वाले कोड बाइट्स को छोड़ सकता हूं?


2
यदि महत्वपूर्ण पात्रों को छोड़ दिया जाता है, तो मैं इसे एक त्रुटि मानता हूं! (यह भी, सवाल कहाँ है?)
अरफांगियन

लगता है जैसे आपको वेब पेज में "नो ब्रेक स्पेस" का सामना करना पड़ा होगा? एक c2बाइट से पहले की आवश्यकता होगी या शायद आपको एक डिकोड त्रुटि मिलेगी
jar

जवाबों:


105

2018 अपडेट:

फरवरी 2018 तक, जैसे कंप्रेशन्स का उपयोग करना काफी लोकप्रियgzip हो गया है (सभी वेबसाइटों के लगभग 73% लोग इसका उपयोग करते हैं, जिसमें Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow और Stack Exchange Network sites जैसी बड़ी साइटें शामिल हैं)।
यदि आप एक सरल डिकोड करते हैं जैसे कि मूल उत्तर में gzipped प्रतिक्रिया के साथ, तो आपको इस तरह की या इसके जैसी त्रुटि मिलेगी:

यूनिकोडडॉफॉर्सेट: 'utf8' कोडक 0x8b को बाइट नहीं कर सकता है 1 स्थिति में: अप्रत्याशित कोड बाइट

एक gzpipped प्रतिक्रिया को डीकोड करने के लिए आपको निम्नलिखित मॉड्यूल (पायथन 3 में) जोड़ने की आवश्यकता है:

import gzip
import io

नोट: अजगर 2 में आप StringIOइसके बजाय का उपयोग करेंगेio

तब आप इस तरह से सामग्री को पार्स कर सकते हैं:

response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource

यह कोड प्रतिक्रिया को पढ़ता है, और बाइट्स को बफर में रखता है। gzipमॉड्यूल तो बफर का उपयोग कर पढ़ता GZipFileकार्य करते हैं। उसके बाद, gzipped फ़ाइल को फिर से बाइट्स में पढ़ा जा सकता है और अंत में सामान्य रूप से पठनीय पाठ को डिकोड किया जा सकता है।

मूल उत्तर 2010 से:

क्या हम वास्तविक मूल्य का उपयोग कर सकते हैं link?

इसके अलावा, हम आमतौर पर इस समस्या का सामना तब करते हैं जब हम .encode()पहले से ही एन्कोडेड बाइट स्ट्रिंग की कोशिश कर रहे होते हैं । तो आप इसे पहले के रूप में डीकोड करने का प्रयास कर सकते हैं

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")

उदहारण के लिए:

html = '\xa0'
encoded_str = html.encode("utf8")

के साथ विफल हो जाता है

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)

जबकि:

html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")

त्रुटि के बिना सफलता। ध्यान दें कि "विंडोज़ -1252" एक ऐसी चीज है जिसका मैंने एक उदाहरण के रूप में उपयोग किया है । मुझे यह चारडेट से मिला और इसमें 0.5 विश्वास था कि यह सही है! (ठीक है, जैसा कि 1-चरित्र-लंबाई स्ट्रिंग के साथ दिया गया है, आप क्या उम्मीद करते हैं) आपको यह बदलना चाहिए कि .urlopen().read()जो सामग्री आपने प्राप्त की थी, उस पर लागू होने वाली बाइट स्ट्रिंग के एन्कोडिंग पर वापस आ जाएगी ।

मेरी एक और समस्या यह है कि .encode()स्ट्रिंग विधि संशोधित स्ट्रिंग लौटाती है और स्रोत को संशोधित नहीं करती है। तो यह बेकार की तरह है self.response.out.write(html)क्योंकि html html.encode से एन्कोडेड स्ट्रिंग नहीं है (यदि ऐसा है तो आप मूल रूप से लक्ष्य कर रहे थे)।

जैसा कि इग्नासियो ने सुझाव दिया था, लौटे स्ट्रिंग के वास्तविक एन्कोडिंग के लिए स्रोत वेबपेज की जाँच करें read()। यह या तो मेटा टैग्स में से एक है या प्रतिक्रिया में ContentType हेडर में। उसके बाद के पैरामीटर के रूप में इसका उपयोग करें .decode()

हालांकि ध्यान दें कि यह नहीं माना जाना चाहिए कि हेडर और / या मेटा चरित्र सेट घोषणाओं को वास्तविक सामग्री से मेल खाने के लिए अन्य डेवलपर्स पर्याप्त जिम्मेदार हैं। (जो एक पीआईटीए है, हाँ, मुझे पता होना चाहिए, मैं उनमें से एक था )।


1
आपके उदाहरण में मुझे लगता है कि आप अंतिम पंक्ति के लिए थे encoded_str = decoded_str.encode("utf8")
अजीथ एंटनी

1
मैंने पायथन 2.7.15 में कोशिश की, और मुझे यह संदेश मिला raise IOError, 'Not a gzipped file'। मैंने क्या गलती की है?
ह्यून-जौन किम

222
>>> u'aあä'.encode('ascii', 'ignore')
'a'

metaप्रतिक्रिया में या Content-Typeशीर्षक में उपयुक्त टैग में charset का उपयोग करके, फिर से प्राप्त स्ट्रिंग को डिकोड करें , फिर एन्कोड करें।

विधि encode(encoding, errors)त्रुटियों के लिए कस्टम हैंडलर स्वीकार करती है। इसके अलावा ignore, डिफ़ॉल्ट मान हैं:

>>> u'aあä'.encode('ascii', 'replace')
b'a??'
>>> u'aあä'.encode('ascii', 'xmlcharrefreplace')
b'a&#12354;&#228;'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\\u3042\\xe4'

Https://docs.python.org/3/library/stdtypes.html#str.encode देखें


119

इग्नासियो वाज़क्वेज़-अब्राम्स के उत्तर के विस्तार के रूप में

>>> u'aあä'.encode('ascii', 'ignore')
'a'

कभी-कभी वर्णों से लहजे को हटाने और आधार फॉर्म को प्रिंट करने के लिए यह वांछनीय है। इससे पूरा किया जा सकता है

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore')
'aa'

आप अन्य वर्णों (जैसे विराम चिह्न) का अपने निकटतम समकक्षों में अनुवाद करना चाह सकते हैं, उदाहरण के लिए RIGHT SINGLE QUOTATION MARK यूनिकोड वर्ण एन्कोसी होने पर ascii APOSTROPHE में परिवर्तित नहीं होता है।

>>> print u'\u2019'

>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
>>> u'\u2019'.encode('ascii', 'ignore')
''
# Note we get an empty string back
>>> u'\u2019'.replace(u'\u2019', u'\'').encode('ascii', 'ignore')
"'"

हालांकि इसे पूरा करने के लिए अधिक कुशल तरीके हैं। अधिक जानकारी के लिए यह प्रश्न देखें कि इस यूनिकोड डेटाबेस के लिए पायथन का "सर्वश्रेष्ठ ASCII" कहां है?


4
दोनों को पूछे गए प्रश्न को संबोधित करने में मददगार था, और उन मुद्दों को संबोधित करने के लिए व्यावहारिक है जो पूछे गए प्रश्न को अंतर्निहित कर सकते हैं। यह इस तरह के प्रश्न का एक मॉडल उत्तर है।
शनुसमाग्नस ३०'१३

96

यूनीडोस्कोप का उपयोग करें - यह भी अजीब वर्णों को तुरंत एससीआई में बदल देता है, और यहां तक ​​कि चीनी को ध्वन्यात्मक एसिसी में भी परिवर्तित करता है।

$ pip install unidecode

फिर:

>>> from unidecode import unidecode
>>> unidecode(u'北京')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'

3
हले-फ़्रीकिन-लुजाह - इसके समय के बारे में मुझे एक जवाब मिला जो मेरे लिए काम करता है
औरिएल पेर्ल्मन

10
मज़ा मूल्य के लिए अपवित्र। ध्यान दें कि यह सभी उच्चारण भाषाओं में शब्द है। स्कोडा स्कोडा नहीं है। स्कोडा सबसे अधिक ईल और होवरक्राफ्ट के साथ कुछ सकल का मतलब है।
सिल्वेन

1
मैं अब तक के दिनों के लिए इंटरनेट पर दस्तखत कर रहा हूँ .... धन्यवाद, बहुत बहुत धन्यवाद
स्टीफन

23

मैं अपने सभी प्रोजेक्ट्स में इस हेल्पर फंक्शन का इस्तेमाल करता हूं। यदि यह यूनिकोड को परिवर्तित नहीं कर सकता है, तो यह इसे अनदेखा करता है। यह एक django लाइब्रेरी में शामिल है, लेकिन एक छोटे से शोध के साथ आप इसे बायपास कर सकते हैं।

from django.utils import encoding

def convert_unicode_to_string(x):
    """
    >>> convert_unicode_to_string(u'ni\xf1era')
    'niera'
    """
    return encoding.smart_str(x, encoding='ascii', errors='ignore')

इसका उपयोग करने के बाद मुझे अब कोई यूनिकोड त्रुटियां नहीं मिली हैं।


10
यह समस्या का निदान और निदान नहीं है। यह कहने जैसा है कि "मैंने अपने पैर काट दिए, मुझे अब कॉर्न्स और गोखरू की समस्या नहीं है"।
जॉन माचिन

10
मैं मानता हूं कि यह समस्या को दबा रहा है। ऐसा लगता है कि प्रश्न के बाद क्या है। उनके नोट को देखें: "क्या मैं त्रुटि को प्राप्त करने के बजाय जो भी कोड बाइट्स की समस्या पैदा कर रहा हूं, उसे छोड़ सकता हूं?"
गैटस्टर

3
यह बिल्कुल वैसा ही है जैसा कि "कुछ-स्ट्रिंग" .encode ('ascii', 'अनदेखा') कहते हैं
यहोशू बर्न्स

17
मैं आपको यह नहीं बता सकता कि एसओ पर सवाल पूछने वाले, और इन सभी उपदेश प्रतिक्रियाओं को लेकर मैं कितना थका हुआ हूं। "मेरी कार शुरू नहीं होगी।" "आप अपनी कार क्यों शुरू करना चाहते हैं? आपको इसके बजाय चलना चाहिए।" इसे रोक!
शन्नुसमाग्निस

8
@ जॉनमोचिन किसी को परवाह नहीं है। मुझे परवाह नहीं है कि आरएसएस के लोगों ने क्या खिलाया है, अगर यह कुछ चरित्र में नहीं है तो इसे छंटनी नहीं हो सकती। उनकी समस्या। मैं सिर्फ यह चाहता हूं कि अजगर वास्तव में इसे ठुकराए और उससे निपटे, मुझे हर बार त्रुटियां न दें, जो मैं 'अनदेखा' करता हूं। कौन उस बकवास के साथ आया था ?!
user1244215

10

टूटी हुई शान्ति जैसे cmd.exeऔर HTML आउटपुट के लिए आप हमेशा उपयोग कर सकते हैं:

my_unicode_string.encode('ascii','xmlcharrefreplace')

शुद्ध ASCII और HTML में प्रिंट करने योग्य बनाते हुए यह सभी गैर-एससीआई चार्ट को संरक्षित करेगा ।

चेतावनी : यदि आप त्रुटियों से बचने के लिए उत्पादन कोड में इसका उपयोग करते हैं तो सबसे अधिक संभावना है कि आपके कोड में कुछ गड़बड़ है । इसके लिए एकमात्र वैध उपयोग मामला गैर-यूनिकोड कंसोल या HTML संस्थाओं में HTML संदर्भ में आसान रूपांतरण के लिए मुद्रण है।

और अंत में, यदि आप विंडोज़ पर हैं और cmd.exe का उपयोग करते हैं तो आप chcp 65001utf-8 आउटपुट (ल्यूसिडा कंसोल के साथ काम करता है) को सक्षम करने के लिए टाइप कर सकते हैं । आपको जोड़ने की आवश्यकता हो सकती है myUnicodeString.encode('utf8')


6

आपने लिखा "" मेरा मानना ​​है कि इसका अर्थ है कि HTML में कहीं न कहीं यूनिकोड में कुछ गलत तरीके से निर्मित प्रयास हैं। ""

HTML को किसी भी तरह के "यूनिकोड में प्रयास", अच्छी तरह से गठित या नहीं होने की उम्मीद नहीं है। यह आवश्यक होना चाहिए कि कुछ एन्कोडिंग में यूनिकोड वर्णों को इनकोड किया गया हो, जिसे आमतौर पर सामने रखा जाता है ... "चारसेट" के लिए देखें।

आप यह मानते हुए प्रतीत होते हैं कि चार्ट UTF-8 ... किस आधार पर है? आपकी त्रुटि संदेश में दिखाया गया "\ xA0" बाइट इंगित करता है कि आपके पास एकल-बाइट चारसेट हो सकता है जैसे cc1252।

यदि आप HTML की शुरुआत में घोषणा से बाहर नहीं निकल सकते हैं, तो संभावना एन्कोडिंग का पता लगाने के लिए चारडेट का उपयोग करने का प्रयास करें ।

आपने "रेगेक्स" के साथ अपने प्रश्न को क्यों टैग किया है?

अपने पूरे प्रश्न को गैर-प्रश्न से बदलने के बाद अपडेट करें:

html = urllib.urlopen(link).read()
# html refers to a str object. To get unicode, you need to find out
# how it is encoded, and decode it.

html.encode("utf8","ignore")
# problem 1: will fail because html is a str object;
# encode works on unicode objects so Python tries to decode it using 
# 'ascii' and fails
# problem 2: even if it worked, the result will be ignored; it doesn't 
# update html in situ, it returns a function result.
# problem 3: "ignore" with UTF-n: any valid unicode object 
# should be encodable in UTF-n; error implies end of the world,
# don't try to ignore it. Don't just whack in "ignore" willy-nilly,
# put it in only with a comment explaining your very cogent reasons for doing so.
# "ignore" with most other encodings: error implies that you are mistaken
# in your choice of encoding -- same advice as for UTF-n :-)
# "ignore" with decode latin1 aka iso-8859-1: error implies end of the world.
# Irrespective of error or not, you are probably mistaken
# (needing e.g. cp1252 or even cp850 instead) ;-)

4

यदि आपके पास एक स्ट्रिंग है line, तो आप .encode([encoding], [errors='strict'])एन्कोडिंग प्रकारों को परिवर्तित करने के लिए स्ट्रिंग्स के लिए विधि का उपयोग कर सकते हैं ।

line = 'my big string'

line.encode('ascii', 'ignore')

पायथन में ASCII और यूनिकोड को संभालने के बारे में अधिक जानकारी के लिए, यह वास्तव में उपयोगी साइट है: https://docs.python.org/2/howto/unicode.html


1
यह तब काम नहीं करता है जब आपके पास स्ट्रिंग में ü जैसा गैर-इस्की चरित्र हो।
साजिद

4

मुझे लगता है कि इसका उत्तर केवल बिट्स और टुकड़ों में है, जो इस तरह की समस्या को जल्दी से ठीक करना मुश्किल बनाता है

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

चलिए एक उदाहरण लेते हैं, मान लीजिए कि मेरे पास फ़ाइल है जिसमें निम्न रूप में कुछ डेटा हैं (ascii और गैर-एएससीआई चार्ट सहित)

1/10/17, 21:36 - भूमि: स्वागत है 21

और हम केवल एएससीआई पात्रों को अनदेखा और संरक्षित करना चाहते हैं।

यह कोड करेगा:

import unicodedata
fp  = open(<FILENAME>)
for line in fp:
    rline = line.strip()
    rline = unicode(rline, "utf-8")
    rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore')
    if len(rline) != 0:
        print rline

और टाइप (rline) आपको देगा

>type(rline) 
<type 'str'>

यह भी (अनस्थिराइज़्ड) "विस्तारित
एस्की

1
unicodestring = '\xa0'

decoded_str = unicodestring.decode("windows-1252")
encoded_str = decoded_str.encode('ascii', 'ignore')

मेरे लिये कार्य करता है


-5

लगता है कि आप अजगर 2.x का उपयोग कर रहे हैं। अजगर 2.x ascii को डिफॉल्ट करता है और इसे यूनिकोड के बारे में नहीं पता है। इसलिए अपवाद।

शेबंग के बाद बस नीचे की रेखा पेस्ट करें, यह काम करेगा

# -*- coding: utf-8 -*-

codingटिप्पणी एक जादू इलाज-सब नहीं है। आपको यह जानने की आवश्यकता है कि त्रुटि क्यों उत्पन्न हो रही है, यह केवल उन चीजों को ठीक करता है जब आपके पायथन स्रोत में खराब वर्ण होते हैं। इस प्रश्न के लिए ऐसा प्रतीत नहीं होता है।
मार्क रैनसम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.