Python: json.loads retorna itens com o prefixo 'u'

161

Receberei uma sequência de caracteres codificada em JSON, Obj-C, e estou decodificando uma sequência fictícia (por enquanto) como o código abaixo. Minha saída sai com o caractere 'u' prefixando cada item:

[{u'i': u'imap.gmail.com', u'p': u'aaaa'}, {u'i': u'333imap.com', u'p': u'bbbb'}...

Como o JSON está adicionando esse caractere unicode? Qual é a melhor maneira de removê-lo?

mail_accounts = []
da = {}
try:
    s = '[{"i":"imap.gmail.com","p":"aaaa"},{"i":"imap.aol.com","p":"bbbb"},{"i":"333imap.com","p":"ccccc"},{"i":"444ap.gmail.com","p":"ddddd"},{"i":"555imap.gmail.com","p":"eee"}]'
    jdata = json.loads(s)
    for d in jdata:
        for key, value in d.iteritems():
            if key not in da:
                da[key] = value
            else:
                da = {}
                da[key] = value
        mail_accounts.append(da)
except Exception, err:
    sys.stderr.write('Exception Error: %s' % str(err))

print mail_accounts
Jane
fonte
7
Python tem um problema aqui. Tudo não é frio. Estou recebendo erros nas strings que o Python cria quando tento gravar essas strings em um arquivo. Por exemplo, quando o python pega "53" do JSON, ele o transforma em u'53 'e tenta gravá-lo em um arquivo como caractere hexadecimal u' \ xe1 ', o que faz com que o Python pegue uma string perfeitamente boa e vomite: JSON: {"sa_BstDeAv": "53", "sa_BwVUpMx" ... PYTHON: {u'sa_BstDeAv ': u'53', u'sa_BwVUpMx '... ERRO AO ESCREVER: Erro de valor (o codec' ascii 'não pode codificar caractere u '\ xe1' na posição 5: ordinal fora do intervalo (128))
David Urry
@ Janehouse a resposta certa aqui é a resposta por jdi Eu realmente acho que você deve mudar isso.
Dekel

Respostas:

168

O prefixo u significa apenas que você tem uma string Unicode. Quando você realmente usa a string, ela não aparece nos seus dados. Não seja jogado pela saída impressa.

Por exemplo, tente o seguinte:

print mail_accounts[0]["i"]

Você não verá um u.

Ned Batchelder
fonte
5
Sua resposta foi o mais útil que eu tenho, e acho que o autor da questão de esta questão teria realmente apreciado que: stackoverflow.com/questions/956867/...
jimh
1
Muito obrigado ! Eu estava confuso para u '' carta por tanto tempo
ketan khandagale
Exceto se você copiar e colar, você tem uma grande quantidade de us nos seus dados. Francamente, imprimir um upara indicar que é uma string Unicode é um dos piores erros do Python. Absolutamente ridículas. Por que não imprimir uma astring antes de cada string, se for ASCII? E ise for um número inteiro?
Snowcrash
No Python 2, as strings Unicode são de um tipo diferente das strings de bytes, portanto, a repr dos dados inclui o prefixo para indicar isso. Não é sobre o conteúdo, é sobre o tipo. O prefixo u é bom se você estiver colando o conteúdo novamente em um programa Python. Caso contrário, talvez você queira usar o json.dumps ().
Ned Batchelder
Você precisa usar a string para pesquisar no dicionário json. no entanto, você não pode usar o operador de ponto.
Maddocks
151

Está tudo bem, cara. O 'u' é uma coisa boa, indica que a string é do tipo Unicode no python 2.x.

http://docs.python.org/2/howto/unicode.html#the-unicode-type

Um homem
fonte
71
Eu gosto do tom muito frio deste. +1 para uma resposta (correta) que me fez sorrir.
mgilson
19
Apenas, relaxe ... (◉Д◉) ┛ 彡 ┻━┻
fulvio
31
Essa foi a resposta mais relaxante que li no StackOverflow.
aanrv
3
☮ ☮ ☮ Peace ☮ ☮ ☮
sr9yar
54

A d3impressão abaixo é a que você está procurando (que é a combinação de lixões e cargas) :)

Tendo:

import json

d = """{"Aa": 1, "BB": "blabla", "cc": "False"}"""

d1 = json.loads(d)              # Produces a dictionary out of the given string
d2 = json.dumps(d)              # Produces a string out of a given dict or string
d3 = json.dumps(json.loads(d))  # 'dumps' gets the dict from 'loads' this time

print "d1:  " + str(d1)
print "d2:  " + d2
print "d3:  " + d3

Impressões:

d1:  {u'Aa': 1, u'cc': u'False', u'BB': u'blabla'}
d2:  "{\"Aa\": 1, \"BB\": \"blabla\", \"cc\": \"False\"}"
d3:  {"Aa": 1, "cc": "False", "BB": "blabla"}
Mercúrio
fonte
3
Hã? json.dumpsconverte o dict de volta em uma string (codificada em JSON). Não era isso que o OP queria fazer. -1.
Mark Amery
10
Mas se você o usar junto com o json.loads, ele produzirá o dicionário sem os caracteres codificados, que é uma resposta para a pergunta (isto é, acima, no d3 print), leia bem a resposta!
Mercury
8

O uprefixo significa que essas cadeias são unicode em vez de cadeias de 8 bits. A melhor maneira de não mostrar o uprefixo é mudar para Python 3, onde as strings são unicode por padrão. Se isso não for uma opção, o strconstrutor converterá de unicode para 8 bits, então simplesmente faça um loop recursivo sobre o resultado e converterá unicodeem str. No entanto, é provavelmente melhor deixar as seqüências como unicode.

Abe Karplus
fonte
8

Unicode é um tipo apropriado aqui. Os documentos JSONDecoder descrevem a tabela de conversão e afirmam que os objetos da string json são decodificados em objetos Unicode

https://docs.python.org/2/library/json.html#encoders-and-decoders

JSON                    Python
==================================
object                  dict
array                   list
string                  unicode
number (int)            int, long
number (real)           float
true                    True
false                   False
null                    None

"codificação determina a codificação usada para interpretar qualquer objeto str decodificado por esta instância (UTF-8 por padrão)."

jdi
fonte
7

Esses caracteres 'u' sendo anexados a um objeto significam que o objeto está codificado em "unicode".

Se você deseja remover os caracteres 'u' do seu objeto, você pode fazer isso:

import json, ast
jdata = ast.literal_eval(json.dumps(jdata)) # Removing uni-code chars

Vamos fazer o checkout do python shell

>>> import json, ast
>>> jdata = [{u'i': u'imap.gmail.com', u'p': u'aaaa'}, {u'i': u'333imap.com', u'p': u'bbbb'}]
>>> jdata = ast.literal_eval(json.dumps(jdata))
>>> jdata
[{'i': 'imap.gmail.com', 'p': 'aaaa'}, {'i': '333imap.com', 'p': 'bbbb'}]
Nivesh Krishna
fonte
Eu sugiro que todo novato simplesmente experimente esse script e pronto, você tem um script para converter ~ da saída ~ u'JSON :) ... se alguém puder apenas adicionar stdin ao script e o formato json no final, você estará pronto para ir!
Jordan Gee
4

Continuei com esse problema ao tentar capturar dados JSON no log com a loggingbiblioteca Python , para fins de depuração e solução de problemas. Obter o upersonagem é um verdadeiro incômodo quando você deseja copiar o texto e colá-lo em seu código em algum lugar.

Como todos dirão, isso ocorre porque é uma representação Unicode e pode vir do fato de você ter usado json.loads() os dados de uma string em primeiro lugar.

Se você deseja a representação JSON no log, sem o uprefixo, o truque é usar json.dumps()antes de fazer logout. Por exemplo:

import json
import logging

# Prepare the data
json_data = json.loads('{"key": "value"}')

# Log normally and get the Unicode indicator
logging.warning('data: {}'.format(json_data))
>>> WARNING:root:data: {u'key': u'value'}

# Dump to a string before logging and get clean output!
logging.warning('data: {}'.format(json.dumps(json_data)))
>>> WARNING:root:data: {'key': 'value'}
Jonatan
fonte
1
Essa realmente deve ser a melhor resposta, os 'u's absolutamente não são "simplesmente despojados" em muitos contextos. Muito obrigado por isso!
Jessica Pennell
1

Tente o seguinte:

mail_accounts [0] .encode ("ascii")

2nd Sight Lab
fonte
Uma resposta sem qualquer explicação é quase inútil. Por favor, tente adicionar algumas informações, como por que isso ajudaria.
Abhilash Chandran
Pessoalmente, acho respostas longas com muita informação desnecessária que distrai. As respostas acima já explicam que o valor é unicode e precisa ser convertido para ascii, portanto não estou repetindo tudo isso. Apenas mostrando uma maneira mais simples de obter o valor. Se alguém tiver problemas para usar esta resposta, basta perguntar e fico feliz em explicar mais! Obrigado
2nd Sight Lab
Esta é realmente a única resposta que mostra concisamente como re-codificar cada string para 'normal' sem passar por um ciclo (o que deve ser ridiculamente ineficiente) json.loads, json.dumps.
Ed Randall
0

Apenas substitua u por uma única citação ...

print (str.replace(mail_accounts,"u'","'"))
Mikematic
fonte