¿Cómo me deshago del prefijo b en una cadena en Python?

87

Muchos de los tweets que estoy importando tienen este problema donde leen

b'I posted a new photo to Facebook'

Recojo el bindica que es un byte. Pero esto está resultando problemático porque en mis archivos CSV que termino escribiendo, bno desaparecen e interfieren en el código futuro.

¿Existe una forma sencilla de eliminar este bprefijo de mis líneas de texto?

Tenga en cuenta que parece que necesito tener el texto codificado en utf-8 o tweepy tiene problemas para sacarlo de la web.


Aquí está el contenido del enlace que estoy analizando:

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

new_tweets = 'content in the link'

Intento de código

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

Error

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
fuente
¿Puedes mostrar al menos parte de esas líneas de texto ?
RomanPerekhrest
@RomanPerekhrest Lo siento, ¿de qué te gustaría más? ¿Código o salida?
Stan Shunpike
Siempre especifique la codificación al abrir archivos.
MKesper

Respuestas:

136

necesitas decodificar el bytesque quieres una cadena:

b = b'1234'
print(b.decode('utf-8'))  # '1234'
hiro protagonista
fuente
Actualicé la pregunta. No creo que este método funcione. Si es así, ¿podría explicar por qué?
Stan Shunpike
4
.encode("utf-8").decode("utf-8")no hace absolutamente nada (si funciona) ... estás en Python 3, ¿verdad? py3 tiene una fuerte distinción entre bytesy str. algo en su código parece usar la cp1252codificación ... podría intentar abrir su archivo con open(..., mode='w', encoding='utf-8')y solo escribir stren el archivo; o te olvidas de toda la codificación y escribes el archivo en binario: open(..., mode='wb')(nota el b) y solo escribe bytes. ¿Eso ayuda?
hiro protagonista
No, eso no lo arregla. Tengo"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
¿Cómo puede saber si se codifica como cp1252? Tampoco pensé .encode("utf-8").decode("utf-8")que haría nada, pero la gente aquí parecía pensar que esa era la respuesta correcta, que no es hasta donde puedo ver.
Stan Shunpike
manchado este camino en el que el rastreo: C:\Users\Stan Shunpike\Anaconda3\lib\encodings\cp1252.py. probablemente debería intentar averiguar cómo / dónde se usa. oh, y estás usando csv.writer; en ese caso, debe escribir strun no bytes. estás recibiendo cosas de requests? la codificación que obtiene de un recurso web puede diferir de utf-8.
hiro protagonista
19

Solo le permite saber que el objeto que está imprimiendo no es una cadena, sino un objeto de byte como un byte literal . La gente explica esto de manera incompleta, así que aquí está mi opinión.

Considere la posibilidad de crear un objeto byte escribiendo un byte literal (literalmente definiendo un objeto byte sin usar realmente un objeto byte, por ejemplo, escribiendo b '') y convirtiéndolo en un objeto de cadena codificado en utf-8. (Tenga en cuenta que convertir aquí 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

Verá que simplemente aplicamos la .decode(utf8)función.

Bytes en Python

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

Los literales de cadena se describen mediante las siguientes definiciones léxicas:

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
fuente
5

Necesita decodificarlo para convertirlo en una cadena. Verifique la respuesta aquí sobre bytes literales en python3 .

In [1]: b'I posted a new photo to Facebook'.decode('utf-8')
Out[1]: 'I posted a new photo to Facebook'
salmanwahed
fuente
1
el problema con esto es que, cuando intento descargar tweets sin el encode("utf-8"), obtengo errores. Y, como mencioné aquí, stackoverflow.com/q/41915383/4422095 eliminar eso no lo resolvió. Incluso si uso la decodificación como sugieres, todavía obtengo un error. Publicaré eso en la publicación.
Stan Shunpike
hecho. no es exactamente lo mismo porque necesitas códigos OAuth de Twitter para hacerlo. pero si simplemente haces el ejemplo que di, obtendrás el mismo problema. no se resuelve con el método sugerido por u. simplemente deshace el utf-8. pero eso no funciona porque no procesará los caracteres en los tweets sin codificación utf-8
Stan Shunpike
Por supuesto, debe utilizar la codificación correcta. utf-8fue un ejemplo.
salmanwahed
4

**** Cómo eliminar los caracteres b '' que son cadenas decodificadas en Python ****

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

En python 3.6 con django 2.0, la decodificación en un byte literal no funciona como se esperaba. Sí, obtengo el resultado correcto cuando lo imprimo, pero el 'valor b' sigue ahí incluso si lo imprime correctamente.

Esto es lo que estoy codificando

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

Esto es lo que estoy decodificando:

uid = force_text(urlsafe_base64_decode(uidb64))

Esto es lo que dice django 2.0:

urlsafe_base64_encode(s)[source]

Codifica una cadena de bytes en base64 para su uso en URL, eliminando cualquier signo igual al final.

urlsafe_base64_decode(s)[source]

Decodifica una cadena codificada en base64, agregando cualquier signo igual al final que pueda haber sido eliminado.


Este es mi archivo 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 es la respuesta de mi consola:

Tipo de contenido: texto / sin formato; charset = "utf-8" Versión MIME: 1.0 Codificación de transferencia de contenido: 7 bits Asunto: Active su cuenta de MySite De: webmaster @ localhost Para: [email protected] Fecha: viernes, 20 de abril de 2018 06:26:46 - 0000 ID de mensaje: <152420560682.16725.4597194169307598579@Dash-U>

Hola, usuario de prueba,

Haga clic en el enlace a continuación para confirmar su registro:

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

como puedes ver uid = b'MjU'

esperado uid = MjU


prueba en consola:

$ 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
>>> 

Después de investigar, parece que está relacionado con Python 3. Mi solución fue bastante simple:

'uid': user.pk,

lo recibo como uidb64 en mi función de activación:

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

y voilá:

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/

ahora funciona bien. :)

Fernando D Jaime
fuente
Creo que el problema no es la decodificación, sino el autoescape desactivado en la plantilla que no puede quitar el byte literal en una cadena como lo hace la decodificación.
Fernando D Jaime
1

Lo hice codificando solo la salida usando utf-8. Aquí está el ejemplo 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)

es decir: no codifique al recopilar datos de la API, codifique la salida (imprimir o escribir) solo.

DevJoe
fuente
0

Suponiendo que no desea volver a decodificarlo inmediatamente, como otros sugieren aquí, puede analizarlo en una cadena y luego simplemente quitar el principio 'by el final '.

>>> 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
fuente
-2

Aunque la pregunta es muy antigua, creo que puede ser útil para quién se enfrenta al mismo problema. Aquí los textos son una cadena como la siguiente:

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

Por lo tanto, no puede eliminar b codificándolo porque no es un byte. Hice lo siguiente para eliminarlo.

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

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

Kamol Roy
fuente
3
No, eso dará "I posted a new photo to Facebook'". De todos modos, esto no es de lo que se trata la pregunta.
tripleee