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>
Stan Shunpike
fonte
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'
Hiro protagonista
fonte
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>
Jonathan Komar
fonte
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'
Salmanwahed
fonte
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)
Avinash Chougule
fonte
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: [email protected] 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: [email protected]
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. :)

Fernando d jaime
fonte
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).

DevJoe
fonte
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"   
Joseph Boyd
fonte
-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"

Kamol Roy
fonte
3
Não, isso vai ceder "I posted a new photo to Facebook'". Não é disso que se trata, de qualquer maneira.
tripleee de