UnicodeEncodeError: le codec 'latin-1' ne peut pas encoder le caractère

93

Quelle pourrait être la cause de cette erreur lorsque j'essaie d'insérer un caractère étranger dans la base de données?

>>UnicodeEncodeError: 'latin-1' codec can't encode character u'\u201c' in position 0: ordinal not in range(256)

Et comment résoudre ce problème?

Merci!

piéger
la source
40
db = MySQLdb.connect (host = "localhost", user = "root", passwd = "", db = "testdb", use_unicode = True, charset = "utf8")
KyungHoon Kim
wow, @KyungHoonKim vous m'avez sauvé la vie! Montez vous allez!
Florian Doyen

Réponses:

64

Le caractère U + 201C Double guillemet gauche n'est pas présent dans le codage Latin-1 (ISO-8859-1).

Il est présent dans la page de codes 1252 (Europe de l'Ouest). Il s'agit d'un encodage spécifique à Windows basé sur ISO-8859-1 mais qui place des caractères supplémentaires dans la plage 0x80-0x9F. La page de code 1252 est souvent confondue avec ISO-8859-1, et c'est un comportement de navigateur Web ennuyeux mais désormais standard que si vous servez vos pages comme ISO-8859-1, le navigateur les traitera à la place comme cp1252. Cependant, ce sont vraiment deux encodages distincts:

>>> u'He said \u201CHello\u201D'.encode('iso-8859-1')
UnicodeEncodeError
>>> u'He said \u201CHello\u201D'.encode('cp1252')
'He said \x93Hello\x94'

Si vous utilisez votre base de données uniquement comme magasin d'octets, vous pouvez utiliser cp1252 pour coder et d'autres caractères présents dans la page de codes Windows Western. Mais encore d'autres caractères Unicode qui ne sont pas présents dans cp1252 provoqueront des erreurs.

Vous pouvez utiliser encode(..., 'ignore')pour supprimer les erreurs en supprimant les caractères, mais vraiment dans ce siècle, vous devriez utiliser UTF-8 à la fois dans votre base de données et vos pages. Cet encodage permet d'utiliser n'importe quel caractère. Vous devriez également idéalement indiquer à MySQL que vous utilisez des chaînes UTF-8 (en définissant la connexion à la base de données et le classement sur les colonnes de chaînes), afin qu'il puisse obtenir une comparaison et un tri insensibles à la casse.

bobince
la source
1
N'est-ce pas cp1252un sur-ensemble strict d'ISO-8859-1? C'est-à-dire que lorsque les navigateurs reçoivent une page ISO-8859-1, ils peuvent la restituer comme s'il s'agissait de CP1252 car il n'y aura de toute façon aucun caractère de la plage 0x80-0x9F.
MSalters
3
Non, les octets 0x80–0x9F ont de vraies affectations dans ISO-8859-1, qui sont remplacées par les ajouts de cp1252 donc ce n'est pas un sur-ensemble. Ils correspondent exactement aux caractères Unicode U + 0080 – U + 009F, qui sont une sélection de caractères de contrôle. Ce sont des caractères de contrôle qui ne sont pas beaucoup utilisés, c'est pourquoi les navigateurs s'en sont sortis, mais c'est ennuyeux lorsque vous essayez de convertir une séquence d'octets en Unicode.
bobince
La seule fois où j'ai vu des caractères de la gamme U + 0080-U + 009F dans un fichier codé en ISO-8859-1 ou UTF-8 résultait d'un clown concaténant un tas de fichiers dont certains étaient codés en cp850 puis transcodage du désordre résultant de "latin1" à UTF-8. Le projet de spécification HTML5 envisage de sanctifier ce comportement très pratique du navigateur (et tout un tas de cas similaires) - voir whatwg.org/specs/web-apps/current-work/multipage/…
John Machin
94

J'ai rencontré ce même problème lors de l'utilisation du module Python MySQLdb. Étant donné que MySQL vous permettra de stocker à peu près toutes les données binaires que vous souhaitez dans un champ de texte quel que soit le jeu de caractères, j'ai trouvé ma solution ici:

Utiliser UTF8 avec Python MySQLdb

Edit: Citation de l'URL ci-dessus pour satisfaire la demande dans le premier commentaire ...

"UnicodeEncodeError: le codec 'latin-1' ne peut pas encoder le caractère ..."

C'est parce que MySQLdb essaie normalement d'encoder tout en latin-1. Cela peut être résolu en exécutant les commandes suivantes juste après avoir établi la connexion:

db.set_character_set('utf8')
dbc.execute('SET NAMES utf8;')
dbc.execute('SET CHARACTER SET utf8;')
dbc.execute('SET character_set_connection=utf8;')

"db" est le résultat de MySQLdb.connect(), et "dbc" est le résultat de db.cursor().

pseudo
la source
1
Il est suggéré que la partie pertinente d'un élément lié soit fournie dans la réponse. Le lien pour une lecture supplémentaire est génial, mais essayez de faire apparaître un résumé dans votre réponse pour ainsi dire :)
Fluffeh
@Fluffeh Et c'était ainsi.
CatShoes
1
grand merci, a fonctionné comme un charme après avoir essayé 1000 autres choses.
Juergen Riemer du
2
Seul db.set_character_set ('utf8') devrait résoudre le problème
Pandurang Patil
21

La meilleure solution est

  1. définir le jeu de caractères de mysql sur 'utf-8'
  2. faire comme ce commentaire (ajouter use_unicode=Trueet charset="utf8")

    db = MySQLdb.connect (host = "localhost", user = "root", passwd = "", db = "testdb", use_unicode = True, charset = "utf8") - KyungHoon Kim 13 mars 14 à 17:04

détail voir:

class Connection(_mysql.connection):

    """MySQL Database Connection Object"""

    default_cursor = cursors.Cursor

    def __init__(self, *args, **kwargs):
        """

        Create a connection to the database. It is strongly recommended
        that you only use keyword parameters. Consult the MySQL C API
        documentation for more information.

        host
          string, host to connect

        user
          string, user to connect as

        passwd
          string, password to use

        db
          string, database to use

        port
          integer, TCP/IP port to connect to

        unix_socket
          string, location of unix_socket to use

        conv
          conversion dictionary, see MySQLdb.converters

        connect_timeout
          number of seconds to wait before the connection attempt
          fails.

        compress
          if set, compression is enabled

        named_pipe
          if set, a named pipe is used to connect (Windows only)

        init_command
          command which is run once the connection is created

        read_default_file
          file from which default client values are read

        read_default_group
          configuration group to use from the default file

        cursorclass
          class object, used to create cursors (keyword only)

        use_unicode
          If True, text-like columns are returned as unicode objects
          using the connection's character set.  Otherwise, text-like
          columns are returned as strings.  columns are returned as
          normal strings. Unicode objects will always be encoded to
          the connection's character set regardless of this setting.

        charset
          If supplied, the connection character set will be changed
          to this character set (MySQL-4.1 and newer). This implies
          use_unicode=True.

        sql_mode
          If supplied, the session SQL mode will be changed to this
          setting (MySQL-4.1 and newer). For more details and legal
          values, see the MySQL documentation.

        client_flag
          integer, flags to use or 0
          (see MySQL docs or constants/CLIENTS.py)

        ssl
          dictionary or mapping, contains SSL connection parameters;
          see the MySQL documentation for more details
          (mysql_ssl_set()).  If this is set, and the client does not
          support SSL, NotSupportedError will be raised.

        local_infile
          integer, non-zero enables LOAD LOCAL INFILE; zero disables

        autocommit
          If False (default), autocommit is disabled.
          If True, autocommit is enabled.
          If None, autocommit isn't set and server default is used.

        There are a number of undocumented, non-standard methods. See the
        documentation for the MySQL C API for some hints on what they do.

        """
Cheney
la source
1
Cette réponse a besoin de plus de votes positifs. Il s'agit d'une solution propre, éliminant la couche d'application des frais généraux d'encodage inutiles.
yeaske
Génial! C'est exactement ce que je cherchais
Geek
De plus, nous ferions mieux de définir utf8mb4pour mysql si vous emojiavez .etc, reportez-vous à quelle-est-la-différence-entre-utf8mb4-et-utf8-charsets-in-mysql
Cheney
20

J'espère que votre base de données est au moins UTF-8. Ensuite, vous devrez exécuter yourstring.encode('utf-8')avant d'essayer de le mettre dans la base de données.

knitti
la source
3

Vous essayez de stocker un point de code Unicode à l' \u201caide d'un codage ISO-8859-1 / Latin-1qui ne peut pas décrire ce point de code. Soit vous devrez peut-être modifier la base de données pour utiliser utf-8 et stocker les données de chaîne en utilisant un encodage approprié, soit vous voudrez peut-être nettoyer vos entrées avant de stocker le contenu; c'est-à-dire en utilisant quelque chose comme l'excellent guide i18n de Sam Ruby . Cela parle des problèmes qui windows-1252peuvent causer et suggère comment le traiter, ainsi que des liens vers un exemple de code!

jabley
la source
2

Les utilisateurs de SQLAlchemy peuvent simplement spécifier leur champ comme convert_unicode=True.

Exemple: sqlalchemy.String(1000, convert_unicode=True)

SQLAlchemy acceptera simplement les objets Unicode et les retournera, en gérant l'encodage lui-même.

Docs

mgojohn
la source
1

Latin-1 (alias ISO 8859-1 ) est un schéma de codage de caractères à octet unique, et vous ne pouvez pas insérer \u201c( ) dans un octet.

Vouliez-vous utiliser l'encodage UTF-8?

msw
la source
1
Latin-1 encode des caractères Unicode spécifiques , mais pas celui-là. Peu importe si \ u201c ne peut pas tenir dans un octet. windows-1252 est un système de codage d'octets également, et ne comprenant \ u201c.
Mark Tolonen
cp1253 (alias windows-1253) est également un schéma de codage de caractères à un octet, et \u0391s'intègre parfaitement dans un octet (en particulier, l'octet 193). Vous voudrez peut -être jeter un coup d'œil à cela ; les gens l'ont trouvé utile.
tzot
Unicode incorpore des glyphes Latin-1 / cp1253 sous forme de points de code 16 bits. Je suis surpris que les commentaires semblent réclamer l'inverse.
msw
1

Utilisez l'extrait ci-dessous pour convertir le texte du latin en anglais

import unicodedata
def strip_accents(text):
    return "".join(char for char in
                   unicodedata.normalize('NFKD', text)
                   if unicodedata.category(char) != 'Mn')

strip_accents('áéíñóúü')

production:

«aeinouu»

Uday Allu
la source
-3

Python: Vous devrez ajouter # - * - codage: UTF-8 - * - (supprimez les espaces autour de *) à la première ligne du fichier python. puis ajoutez ce qui suit au texte à encoder: .encode ('ascii', 'xmlcharrefreplace') . Cela remplacera tous les caractères Unicode par son équivalent ASCII.

nids
la source