Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python + PostgreSQL + strange ascii = UTF8 encoding error

I have ascii strings which contain the character "\x80" to represent the euro symbol:

>>> print "\x80"
€

When inserting string data containing this character into my database, I get:

psycopg2.DataError: invalid byte sequence for encoding "UTF8": 0x80
HINT:  This error can also happen if the byte sequence does not match the encodi
ng expected by the server, which is controlled by "client_encoding".

I'm a unicode newbie. How can I convert my strings containing "\x80" to valid UTF-8 containing that same euro symbol? I've tried calling .encode and .decode on various strings, but run into errors:

>>> "\x80".encode("utf-8")
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    "\x80".encode("utf-8")
UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128)
like image 953
Claudiu Avatar asked Jun 07 '10 17:06

Claudiu


People also ask

Are Python strings Unicode or Unicode?

If you use Python 3, all strings are natively in unicode, and you can specify the encoding when opening a file. You code could become: Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share your research!

How can I fix the UTF-8 encoding problem in Windows 10?

Change the application to use LATIN1 or (better) UTF-8 internally and set the client encoding appropriately. Using UTF-8 everywhere would have the advantage that you are safe from this kind of problem. Triggered by UTF-8 everywhere (on windows 10), I tried several approaches.

How to convert a string to Unicode on Mac?

On Mac OS X I get the correct output by simply printing the "w\xc4\x85\xc5\xbc" thing. Make sure your terminal supports unicode. You could also try decode instead of encode to convert the string into a unicode object. You can't possibly be actually receiving that word in ASCII, as the second and third characters aren't representable in ASCII.

Why can't I receive a word in ASCII?

You can't possibly be actually receiving that word in ASCII, as the second and third characters aren't representable in ASCII. It's likely that the web service is using UTF-8, but not guaranteed. Like Alex, I suspect a lot of your display issues are due to your terminal.


1 Answers

The question starts with a false premise:

I have ascii strings which contain the character "\x80" to represent the euro symbol.

ASCII characters are in the range "\x00" to "\x7F" inclusive.

The previously-accepted now-deleted answer operated under two gross misapprehensions (1) that locale == encoding (2) that the latin1 encoding maps "\x80" to a Euro character.

In fact, all of the ISO-8859-x encodings map "\x80" to U+0080 which is one of the C1 control characters, not a Euro character. Only 3 of those encodings (x in (7, 15, 16)) provide the Euro character, as "\xA4". See this Wikipedia article.

You need to know what encoding your data is in. What machine was it created on? How? The locale it was created in (not necessarily yours) may give you a clue.

Note that "My data is encoded in latin1" is up there with "The cheque's in the mail" and "Of course I'll love you in the morning". Your data is probably encoded in one of the cp125x encodings found on Windows platforms. Note that all of them except cp1251 (Windows Cyrillic) map "\x80" to the euro character:

>>> ['\x80'.decode('cp125' + str(x), 'replace') for x in range(9)]
[u'\u20ac', u'\u0402', u'\u20ac', u'\u20ac', u'\u20ac', u'\u20ac', u'\u20ac', u'\u20ac', u'\u20ac']

Update in response to the OP's comment

I'm reading this data from a file, e.g. open(fname).read(). It contains strings with \x80 in them that represents the euro character. it's just a plain text file. it is generated by another program, but I don't know how it goes about generating the text. what would be a good solution? I'm thinking I can assume that it outputs "\x80" for a euro character, meaning I can assume it's encoded with a cp125x that has that char as the euro.

This is a bit confusing: First you say

It contains strings with \x80 in them that represents the euro character

But later you say

I'm thinking I can assume that it outputs "\x80" for a euro character

Please explain.

Selecting an appropriate cp125x encoding: Where (geographical location) was the file created? In what language(s) is the text written? Any characters other than the presumed euro with values > "\x7f"? If so, which ones and what context are they used in?

Update 2 If you don't "know how the program is written", neither you nor we can form an opinion on whether it always uses "\x80" for the euro character. Although doing otherwise would be monumental silliness, it can't be ruled out.

If the text is written in the English language and/or it is written in the USA, and/or it's written on a Windows platform, then it's reasonably certain that cp1252 is the way to go ... until you get evidence to the contrary, in which case you'd need to guess an encoding by yourself or answer the (what language, what locality) questions.

like image 158
John Machin Avatar answered Sep 28 '22 20:09

John Machin