UnicodeEncodeError: o codec 'latin-1' não pode codificar caracteres

93

O que pode estar causando esse erro quando tento inserir um caractere estrangeiro no banco de dados?

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

E como faço para resolver isso?

Obrigado!

enredar
fonte
40
db = MySQLdb.connect (host = "localhost", user = "root", passwd = "", db = "testdb", use_unicode = True, charset = "utf8")
KyungHoon Kim
uau, @KyungHoonKim você salvou minha vida! Vá para cima!
Florian Doyen

Respostas:

64

O caractere U + 201C Aspas duplas à esquerda não está presente na codificação Latin-1 (ISO-8859-1).

Ele está presente na página de código 1252 (Europa Ocidental). Esta é uma codificação específica do Windows baseada em ISO-8859-1, mas que coloca caracteres extras no intervalo 0x80-0x9F. A página de código 1252 é freqüentemente confundida com ISO-8859-1, e é um comportamento irritante, mas agora padrão, do navegador da web, se você servir suas páginas como ISO-8859-1, o navegador as tratará como cp1252. No entanto, eles realmente são duas codificações distintas:

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

Se você estiver usando seu banco de dados apenas como um armazenamento de bytes, você pode usar cp1252 para codificar e outros caracteres presentes na página de código do Windows Western. Mas ainda outros caracteres Unicode que não estão presentes em cp1252 causarão erros.

Você pode usar encode(..., 'ignore')para suprimir os erros livrando-se dos caracteres, mas realmente neste século você deve usar UTF-8 em seu banco de dados e em suas páginas. Esta codificação permite que qualquer caractere seja usado. Idealmente, você também deve informar ao MySQL que está usando strings UTF-8 (definindo a conexão do banco de dados e o agrupamento em colunas de string), para que possa obter comparação e classificação sem distinção entre maiúsculas e minúsculas.

bobince
fonte
1
Não é cp1252um superconjunto estrito de ISO-8859-1? Ou seja, quando os navegadores recebem uma página ISO-8859-1, eles podem renderizá-la como se fosse CP1252, porque não haverá nenhum caractere do intervalo de 0x80-0x9Fqualquer maneira.
MSalters de
3
Não, os bytes 0x80–0x9F têm atribuições reais em ISO-8859-1, que são substituídas pelas adições de cp1252, portanto não é um superconjunto. Eles são mapeados exatamente para os caracteres Unicode U + 0080 – U + 009F, que são uma seleção de caracteres de controle. Eles são caracteres de controle que não são muito usados, e é por isso que os navegadores se safaram, mas é irritante quando você está tentando converter uma sequência de bytes em Unicode.
bobince
A única vez que vi caracteres no intervalo U + 0080-U + 009F em um arquivo codificado como ISO-8859-1 ou UTF-8 resultou de algum palhaço concatenando um monte de arquivos, alguns dos quais foram codificados em cp850 e então transcodificar a bagunça resultante de "latin1" para UTF-8. O rascunho da especificação HTML5 está considerando santificar esse comportamento muito prático do navegador (e um monte de casos semelhantes) - consulte whatwg.org/specs/web-apps/current-work/multipage/…
John Machin
94

Encontrei esse mesmo problema ao usar o módulo Python MySQLdb. Como o MySQL permite que você armazene praticamente todos os dados binários que desejar em um campo de texto, independentemente do conjunto de caracteres, encontrei minha solução aqui:

Usando UTF8 com Python MySQLdb

Editar: citação do URL acima para atender à solicitação no primeiro comentário ...

"UnicodeEncodeError: o codec 'latin-1' não pode codificar o caractere ..."

Isso ocorre porque o MySQLdb normalmente tenta codificar tudo para latin-1. Isso pode ser corrigido executando os seguintes comandos logo depois de estabelecer a conexão:

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

"db" é o resultado de MySQLdb.connect()e "dbc" é o resultado de db.cursor().

usuario
fonte
1
Sugere-se que a parte relevante de um item vinculado seja fornecida na resposta. O link para leitura extra é ótimo, mas por favor, tente colocar um resumo executivo em sua resposta, por assim dizer :)
Fluffeh
@Fluffeh E assim foi.
CatShoes
1
muito obrigado, funcionou como um encanto depois de tentar 1000 outras coisas.
Juergen Riemer
2
Apenas db.set_character_set ('utf8') deve resolver o problema
Pandurang Patil
21

A melhor solução é

  1. definir o conjunto de caracteres do mysql para 'utf-8'
  2. goste deste comentário (adicionar use_unicode=Truee charset="utf8")

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

detalhe veja:

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
fonte
1
Esta resposta precisa de mais votos positivos. Esta é uma solução limpa, limpando a camada de aplicativo de sobrecargas de codificação desnecessárias.
yeaske,
Ótimo! Isso é exatamente o que eu estava procurando
Geek de
Além disso, é melhor definir utf8mb4para mysql se tiver emoji.etc, consulte qual-é-a-diferença-entre-utf8mb4-and-utf8-charsets-in-mysql
Cheney
20

Espero que seu banco de dados seja pelo menos UTF-8. Em seguida, você precisará executar yourstring.encode('utf-8')antes de tentar colocá-lo no banco de dados.

tricô
fonte
3

Você está tentando armazenar um ponto de código Unicode \u201cusando uma codificação ISO-8859-1 / Latin-1que não pode descrever esse ponto de código. Você pode precisar alterar o banco de dados para usar utf-8 e armazenar os dados da string usando uma codificação apropriada, ou pode desejar limpar suas entradas antes de armazenar o conteúdo; ou seja, usando algo como o excelente guia i18n de Sam Ruby . Ele fala sobre os problemas que windows-1252podem causar e sugere como processá-lo, além de links para exemplos de código!

jabley
fonte
2

Os usuários do SQLAlchemy podem simplesmente especificar seus campos como convert_unicode=True .

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

SQLAlchemy simplesmente aceitará objetos Unicode e os retornará, tratando da própria codificação.

Docs

mgojohn
fonte
1

Latin-1 (também conhecido como ISO 8859-1 ) é um esquema de codificação de caracteres de octeto único, e você não pode ajustar \u201c( ) em um byte.

Você quis dizer usar a codificação UTF-8?

msw
fonte
1
O Latin-1 codifica caracteres Unicode específicos , mas não aquele. Não importa se \ u201c não cabe em um byte. windows-1252 é um sistema único octeto codificação também, e não incluindo \ u201c.
Mark Tolonen,
cp1253 (também conhecido como windows-1253) também é um esquema de codificação de caractere de octeto único e, ainda assim, \u0391se encaixa perfeitamente em um byte (especificamente, byte 193). Você pode querer dar uma olhada nisso ; as pessoas acharam útil.
tzot de
O Unicode incorpora os glifos Latin-1 / cp1253 como codepoints de 16 bits. Estou surpreso que os comentários pareçam alegar o contrário.
msw
1

Use o snippet abaixo para converter o texto do latim para o inglês

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

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

resultado:

'aeinouu'

Uday Allu
fonte
-3

Python: você precisará adicionar # - * - coding: UTF-8 - * - (remover os espaços ao redor de *) à primeira linha do arquivo python. e então adicione o seguinte ao texto para codificar: .encode ('ascii', 'xmlcharrefreplace') . Isso substituirá todos os caracteres Unicode por seu equivalente ASCII.

nids
fonte