Python Unicode Encode Error
Asked Answered
K

9

116

I'm reading and parsing an Amazon XML file and while the XML file shows a ' , when I try to print it I get the following error:

'ascii' codec can't encode character u'\u2019' in position 16: ordinal not in range(128) 

From what I've read online thus far, the error is coming from the fact that the XML file is in UTF-8, but Python wants to handle it as an ASCII encoded character. Is there a simple way to make the error go away and have my program print the XML as it reads?

Karlin answered 11/7, 2010 at 19:0 Comment(2)
I was just coming to SO to post this question. Is there an easy way to sanitize a string for unicode()?Kaela
Please check also this answer to a related question: “Python UnicodeDecodeError - Am I misunderstanding encode?”Marley
D
204

Likely, your problem is that you parsed it okay, and now you're trying to print the contents of the XML and you can't because theres some foreign Unicode characters. Try to encode your unicode string as ascii first:

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

the 'ignore' part will tell it to just skip those characters. From the python docs:

>>> # Python 2: u = unichr(40960) + u'abcd' + unichr(1972)
>>> u = chr(40960) + u'abcd' + chr(1972)
>>> u.encode('utf-8')
'\xea\x80\x80abcd\xde\xb4'
>>> u.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in position 0: ordinal not in range(128)
>>> u.encode('ascii', 'ignore')
'abcd'
>>> u.encode('ascii', 'replace')
'?abcd?'
>>> u.encode('ascii', 'xmlcharrefreplace')
'&#40960;abcd&#1972;'

You might want to read this article: http://www.joelonsoftware.com/articles/Unicode.html, which I found very useful as a basic tutorial on what's going on. After the read, you'll stop feeling like you're just guessing what commands to use (or at least that happened to me).

Detect answered 11/7, 2010 at 19:10 Comment(6)
I'm trying to make the following string safe: ' foo “bar bar” df'(note the curly quotes), but the above still fails for me.Kaela
@Rosarch: Fails how? same error? And which error-handling rule did you use?Detect
@Rosarch, your problem is probably earlier. Try this code: # -- coding: latin-1 -- u = u' foo “bar bar” df' print u.encode('ascii', 'ignore') For you, it was probably converting your string INTO unicode given the encoding you specified for the python scrip that threw the error.Detect
I went ahead and made my issue into its own question: #3224927Kaela
.encode('ascii', 'ignore') loses data unnecessarily even if OP's environment may support non-ascii characters (most cases)Broadnax
This solved my problem after struggling with different things for one hour.Windage
D
17

A better solution:

if type(value) == str:
    # Ignore errors even if the string is not proper UTF-8 or has
    # broken marker bytes.
    # Python built-in function unicode() can do this.
    value = unicode(value, "utf-8", errors="ignore")
else:
    # Assume the value object has proper __unicode__() method
    value = unicode(value)

If you would like to read more about why:

http://docs.plone.org/manage/troubleshooting/unicode.html#id1

Defluxion answered 9/1, 2014 at 20:24 Comment(1)
It does not help with OP's issue: "can't encode character u'\u2019'". u'\u2019 is already Unicode.Broadnax
B
8

Don't hardcode the character encoding of your environment inside your script; print Unicode text directly instead:

assert isinstance(text, unicode) # or str on Python 3
print(text)

If your output is redirected to a file (or a pipe); you could use PYTHONIOENCODING envvar, to specify the character encoding:

$ PYTHONIOENCODING=utf-8 python your_script.py >output.utf8

Otherwise, python your_script.py should work as is -- your locale settings are used to encode the text (on POSIX check: LC_ALL, LC_CTYPE, LANG envvars -- set LANG to a utf-8 locale if necessary).

To print Unicode on Windows, see this answer that shows how to print Unicode to Windows console, to a file, or using IDLE.

Broadnax answered 29/6, 2015 at 7:46 Comment(0)
S
2

Excellent post : http://www.carlosble.com/2010/12/understanding-python-and-unicode/

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

def __if_number_get_string(number):
    converted_str = number
    if isinstance(number, int) or \
            isinstance(number, float):
        converted_str = str(number)
    return converted_str


def get_unicode(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode
    return unicode(strOrUnicode, encoding, errors='ignore')


def get_string(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode.encode(encoding)
    return strOrUnicode
Suicidal answered 13/9, 2016 at 18:31 Comment(0)
M
0

You can use something of the form

s.decode('utf-8')

which will convert a UTF-8 encoded bytestring into a Python Unicode string. But the exact procedure to use depends on exactly how you load and parse the XML file, e.g. if you don't ever access the XML string directly, you might have to use a decoder object from the codecs module.

Mccombs answered 11/7, 2010 at 19:4 Comment(3)
It's already encoded in UTF-8 The error is specifically: myStrings = deque([u'Dorf and Svoboda\u2019s text builds on the str... and Computer Engineering\u2019s subdisciplines.']) The string is in UTF-8 as you can see, but it gets mad about the internal '\u2019'Karlin
Oh, OK, I thought you were having a different problem.Mccombs
@Alex B: No, the string is Unicode, not Utf-8. To encode it as Utf-8 use '...'.encode('utf-8')Spires
C
0

I wrote the following to fix the nuisance non-ascii quotes and force conversion to something usable.

unicodeToAsciiMap = {u'\u2019':"'", u'\u2018':"`", }

def unicodeToAscii(inStr):
    try:
        return str(inStr)
    except:
        pass
    outStr = ""
    for i in inStr:
        try:
            outStr = outStr + str(i)
        except:
            if unicodeToAsciiMap.has_key(i):
                outStr = outStr + unicodeToAsciiMap[i]
            else:
                try:
                    print "unicodeToAscii: add to map:", i, repr(i), "(encoded as _)"
                except:
                    print "unicodeToAscii: unknown code (encoded as _)", repr(i)
                outStr = outStr + "_"
    return outStr
Cootie answered 10/9, 2015 at 11:31 Comment(0)
G
0

If you need to print an approximate representation of the string to the screen, rather than ignoring those nonprintable characters, please try unidecode package here:

https://pypi.python.org/pypi/Unidecode

The explanation is found here:

https://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/

This is better than using the u.encode('ascii', 'ignore') for a given string u, and can save you from unnecessary headache if character precision is not what you are after, but still want to have human readability.

Wirawan

Garamond answered 23/11, 2016 at 18:16 Comment(0)
M
-1

Try adding the following line at the top of your python script.

# _*_ coding:utf-8 _*_
Manofwar answered 20/1, 2016 at 5:8 Comment(0)
M
-2

Python 3.5, 2018

If you don't know what the encoding but the unicode parser is having issues you can open the file in Notepad++ and in the top bar select Encoding->Convert to ANSI. Then you can write your python like this

with open('filepath', 'r', encoding='ANSI') as file:
    for word in file.read().split():
        print(word)
Markos answered 9/10, 2018 at 21:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.