Como faço para me livrar do prefixo b em uma string em python?


87

Muitos dos tweets que estou importando estão tendo esse problema de leitura

b'I posted a new photo to Facebook'

Percebi que bindica que é um byte. Mas isso está se mostrando problemático porque em meus arquivos CSV que acabo escrevendo, o arquivo bnão desaparece e está interferindo no código futuro.

Existe uma maneira simples de remover esse bprefixo de minhas linhas de texto?

Lembre-se de que preciso ter o texto codificado em utf-8 ou tweepy e tem problemas para puxá-lo da web.


Este é o conteúdo do link que estou analisando:

https://www.dropbox.com/s/sjmsbuhrghj7abt/new_tweets.txt?dl=0

new_tweets = 'content in the link'

Tentativa de código

outtweets = [[tweet.text.encode("utf-8").decode("utf-8")] for tweet in new_tweets]
print(outtweets)

Erro

UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-21-6019064596bf> in <module>()
      1 for screen_name in user_list:
----> 2     get_all_tweets(screen_name,"instance file")

<ipython-input-19-e473b4771186> in get_all_tweets(screen_name, mode)
     99             with open(os.path.join(save_location,'%s.instance' % screen_name), 'w') as f:
    100                 writer = csv.writer(f)
--> 101                 writer.writerows(outtweets)
    102         else:
    103             with open(os.path.join(save_location,'%s.csv' % screen_name), 'w') as f:

C:\Users\Stan Shunpike\Anaconda3\lib\encodings\cp1252.py in encode(self, input, final)
     17 class IncrementalEncoder(codecs.IncrementalEncoder):
     18     def encode(self, input, final=False):
---> 19         return codecs.charmap_encode(input,self.errors,encoding_table)[0]
     20 
     21 class IncrementalDecoder(codecs.IncrementalDecoder):

UnicodeEncodeError: 'charmap' codec can't encode characters in position 64-65: character maps to <undefined>

você pode mostrar pelo menos parte dessas linhas de texto ?
— RomanPerekhrest

@RomanPerekhrest, desculpe, do que você gostaria mais? Código ou saída?
— Stan Shunpike

Sempre especifique a codificação ao abrir arquivos.
— MKesper

Respostas:


136

você precisa decodificar o bytesque deseja uma string:

b = b'1234'
print(b.decode('utf-8'))  # '1234'

Eu atualizei a pergunta. Não acho que esse método funcione. Se sim, você poderia explicar por quê?
— Stan Shunpike

4
.encode("utf-8").decode("utf-8")não faz absolutamente nada (se é que funciona) ... você está no python 3, certo? py3 tem uma forte distinção entre bytese str. algo em seu código parece usar a cp1252codificação ... você pode tentar abrir seu arquivo com open(..., mode='w', encoding='utf-8')e apenas gravar strno arquivo; ou você se esquece de toda a codificação e escreve o arquivo em binário: open(..., mode='wb')(observe o b) e apenas escreve bytes. Isso ajuda?
— protagonista hiro

Não, isso não resolve. Eu tenho"b'Due to the storms this weekend, we have rescheduled the Blumenfield Bike Ride for Feb 26. Hope to see you there.\xe2\x80\xa6'"
— Stan Shunpike

Como você pode saber se ele codifica como cp1252? Também não achei .encode("utf-8").decode("utf-8")que faria nada, mas as pessoas aqui pareciam pensar que era a resposta certa, o que não é pelo que vejo.
— Stan Shunpike

i visto este caminho em você traceback: C:\Users\Stan Shunpike\Anaconda3\lib\encodings\cp1252.py. você provavelmente deve tentar descobrir como / onde isso é usado. oh, e você está usando o csv.writer; nesse caso, você strrealmente precisa escrever um não bytes. você está recebendo coisas requests? a codificação que você obtém de um recurso da web pode ser diferente utf-8.
— protagonista hiro

19

Ele apenas informa que o objeto que você está imprimindo não é uma string, e sim um objeto de byte como um literal de byte . As pessoas explicam isso de maneiras incompletas, então aqui está minha opinião.

Considere a criação de um objeto de byte digitando um literal de byte (literalmente definindo um objeto de byte sem realmente usar um objeto de byte, por exemplo, digitando b '') e convertendo-o em um objeto de string codificado em utf-8. (Observe que converter aqui significa decodificar )

byte_object= b"test" # byte object by literally typing characters
print(byte_object) # Prints b'test'
print(byte_object.decode('utf8')) # Prints "test" without quotations

Você vê que simplesmente aplicamos a .decode(utf8)função.

Bytes em Python

https://docs.python.org/3.3/library/stdtypes.html#bytes

Literais de string são descritos pelas seguintes definições lexicais:

https://docs.python.org/3.3/reference/lexical_analysis.html#string-and-bytes-literals

stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix    ::=  "r" | "u" | "R" | "U"
shortstring     ::=  "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring      ::=  "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::=  shortstringchar | stringescapeseq
longstringitem  ::=  longstringchar | stringescapeseq
shortstringchar ::=  <any source character except "\" or newline or the quote>
longstringchar  ::=  <any source character except "\">
stringescapeseq ::=  "\" <any source character>

bytesliteral   ::=  bytesprefix(shortbytes | longbytes)
bytesprefix    ::=  "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes     ::=  "'" shortbytesitem* "'" | '"' shortbytesitem* '"'
longbytes      ::=  "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""'
shortbytesitem ::=  shortbyteschar | bytesescapeseq
longbytesitem  ::=  longbyteschar | bytesescapeseq
shortbyteschar ::=  <any ASCII character except "\" or newline or the quote>
longbyteschar  ::=  <any ASCII character except "\">
bytesescapeseq ::=  "\" <any ASCII character>

5

Você precisa decodificá-lo para convertê-lo em uma string. Verifique a resposta aqui sobre bytes literais em python3 .

In [1]: b'I posted a new photo to Facebook'.decode('utf-8')
Out[1]: 'I posted a new photo to Facebook'

1
o problema com isso é que, quando tento baixar tweets sem os encode("utf-8")erros, recebo. E, como mencionei aqui, stackoverflow.com/q/41915383/4422095 remover isso não resolveu o problema. Mesmo se eu usar a decodificação como você sugeriu, ainda recebo um erro. Vou postar isso no post.
— Stan Shunpike

feito. não é exatamente o mesmo porque você precisa de códigos OAuth do Twitter para fazer isso. mas se você apenas fizer o exemplo que dei, você terá o mesmo problema. não é resolvido pelo método que você sugeriu. ele apenas desfaz o utf-8. mas isso não funciona porque não processa os caracteres nos tweets sem codificação utf-8
— Stan Shunpike

Você tem que usar a codificação correta, é claro. utf-8foi um exemplo.
— salmanwahed

4

**** Como remover b '' chars que são strings decodificadas em python ****

import base64
a='cm9vdA=='
b=base64.b64decode(a).decode('utf-8')
print(b)

2

No python 3.6 com django 2.0, decodificar em um literal de byte não funciona como esperado. Sim, obtenho o resultado certo quando imprimo, mas o b'value 'ainda está lá, mesmo que você imprima corretamente.

Isso é o que estou codificando

uid': urlsafe_base64_encode(force_bytes(user.pk)),

Isso é o que estou decodificando:

uid = force_text(urlsafe_base64_decode(uidb64))

Isso é o que django 2.0 diz:

urlsafe_base64_encode(s)[source]

Codifica uma sequência de bytes em base64 para uso em URLs, removendo quaisquer sinais de igual à direita.

urlsafe_base64_decode(s)[source]

Decodifica uma string codificada em base64, adicionando de volta quaisquer sinais de igual à direita que possam ter sido removidos.


Este é meu arquivo account_activation_email_test.html

{% autoescape off %}
Hi {{ user.username }},

Please click on the link below to confirm your registration:

http://{{ domain }}{% url 'accounts:activate' uidb64=uid token=token %}
{% endautoescape %}

Esta é a minha resposta do console:

Tipo de conteúdo: texto / simples; charset = "utf-8" Versão MIME: 1.0 Content-Transfer-Encoding: 7bit Assunto: Ative sua conta do MySite De: webmaster @ localhost Para: testuser@yahoo.com Data: Sex, 20 Abr 2018 06:26:46 - 0000 Message-ID: <152420560682.16725.4597194169307598579@Dash-U>

Olá, testuser,

Clique no link abaixo para confirmar seu registro:

http://127.0.0.1:8000/activate/b'MjU'/4vi-fasdtRf2db2989413ba/

como você pode ver uid = b'MjU'

esperado uid = MjU


teste no console:

$ python
Python 3.6.4 (default, Apr  7 2018, 00:45:33) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
>>> from django.utils.encoding import force_bytes, force_text
>>> var1=urlsafe_base64_encode(force_bytes(3))
>>> print(var1)
b'Mw'
>>> print(var1.decode())
Mw
>>> 

Depois de investigar, parece que está relacionado ao python 3. Minha solução alternativa foi bastante simples:

'uid': user.pk,

eu recebo como uidb64 na minha função de ativação:

user = User.objects.get(pk=uidb64)

e voila:

Content-Transfer-Encoding: 7bit
Subject: Activate Your MySite Account
From: webmaster@localhost
To: testuser@yahoo.com
Date: Fri, 20 Apr 2018 20:44:46 -0000
Message-ID: <152425708646.11228.13738465662759110946@Dash-U>


Hi testuser,

Please click on the link below to confirm your registration:

http://127.0.0.1:8000/activate/45/4vi-3895fbb6b74016ad1882/

agora funciona bem. :)


Acredito que o problema não seja a decodificação, mas sim o autoescape desativado no modelo, que não consegue separar o literal de byte em uma string exatamente como a decodificação.
— Fernando D Jaime

1

Eu fiz isso codificando apenas a saída usando utf-8. Aqui está o exemplo de código

new_tweets = api.GetUserTimeline(screen_name = user,count=200)
result = new_tweets[0]
try: text = result.text
except: text = ''

with open(file_name, 'a', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerows(text)

ou seja: não codifique ao coletar dados da API, codifique apenas a saída (impressão ou gravação).


0

Assumindo que você não deseja decodificá-lo imediatamente como os outros estão sugerindo aqui, você pode analisá-lo em uma string e, em seguida, remover o início 'be o fim '.

>>> x = "Hi there 😄" 
>>> x = "Hi there 😄".encode("utf-8") 
>>> x
b"Hi there \xef\xbf\xbd"
>>> str(x)[2:-1]
"Hi there \\xef\\xbf\\xbd"   

-2

Embora a questão seja muito antiga, acho que pode ser útil para quem está enfrentando o mesmo problema. Aqui, os textos são uma string como abaixo:

text= "b'I posted a new photo to Facebook'"

Portanto, você não pode remover b codificando-o porque não é um byte. Eu fiz o seguinte para removê-lo.

cleaned_text = text.split("b'")[1]

que vai dar "I posted a new photo to Facebook"


3
Não, isso vai ceder "I posted a new photo to Facebook'". Não é disso que se trata, de qualquer maneira.
— tripleee de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.