Comment puis-je me débarrasser du préfixe b dans une chaîne en python?

87

Un certain nombre de tweets que j'importe ont ce problème là où ils lisent

b'I posted a new photo to Facebook'

Je rassemble le bindique que c'est un octet. Mais cela s'avère problématique car dans mes fichiers CSV que je finis par écrire, le bne disparaît pas et interfère dans le code futur.

Existe-t-il un moyen simple de supprimer ce bpréfixe de mes lignes de texte?

Gardez à l'esprit que je semble avoir besoin d'avoir le texte encodé en utf-8 ou tweepy a du mal à les extraire du Web.


Voici le contenu du lien que j'analyse:

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

new_tweets = 'content in the link'

Tentative de code

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

Erreur

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
la source
pouvez-vous afficher au moins une partie de ces lignes de texte ?
RomanPerekhrest
@RomanPerekhrest Je suis désolé, qu'est-ce que vous aimeriez plus? Code ou sortie?
Stan Shunpike
Spécifiez toujours l'encodage lors de l'ouverture des fichiers.
MKesper
1
Possibilité de duplication de Suppress / print sans préfixe b 'pour les octets en Python 3
wesinat0r

Réponses:

136

vous devez décoder le bytesde vous voulez une chaîne:

b = b'1234'
print(b.decode('utf-8'))  # '1234'
protagoniste de hiro
la source
J'ai mis à jour la question. Je ne pense pas que cette méthode fonctionne. Si c'est le cas, pourriez-vous expliquer pourquoi?
Stan Shunpike
4
.encode("utf-8").decode("utf-8")ne fait absolument rien (si ça marche du tout) ... vous êtes sur python 3, non? py3 a une forte distinction entre byteset str. quelque chose dans votre code semble utiliser l' cp1252encodage ... vous pouvez essayer d'ouvrir votre fichier avec open(..., mode='w', encoding='utf-8')et n'écrire que strdans le fichier; ou vous oubliez tout l'encodage et écrivez le fichier en binaire: open(..., mode='wb')(notez le b) et écrivez seulement bytes. Est ce que ça aide?
hiro protagonist
Non, cela ne résout pas le problème. J'ai"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
Comment pouvez-vous dire qu'il code en tant que cp1252? Je ne pensais pas non plus que .encode("utf-8").decode("utf-8")je ferais quoi que ce soit, mais les gens ici semblaient penser que c'était la bonne réponse, ce qui n'est pas aussi loin que je peux voir.
Stan Shunpike
i repéré ce chemin en vous retraçage: C:\Users\Stan Shunpike\Anaconda3\lib\encodings\cp1252.py. vous devriez probablement essayer de savoir comment / où cela est utilisé. oh, et vous utilisez le csv.writer; dans ce cas, vous devez en streffet écrire un non bytes. obtenez-vous des choses requests? l'encodage obtenu à partir d'une ressource Web peut différer de utf-8.
hiro protagonist
19

Cela vous permet simplement de savoir que l'objet que vous imprimez n'est pas une chaîne, mais plutôt un objet octet sous forme de littéral d'octet . Les gens expliquent cela de manière incomplète, voici donc mon avis.

Envisagez de créer un objet octet en tapant un littéral octet (définissant littéralement un objet octet sans utiliser réellement un objet octet, par exemple en tapant b '') et en le convertissant en un objet chaîne codé en utf-8. (Notez que convertir ici signifie décoder )

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

Vous voyez que nous appliquons simplement la .decode(utf8)fonction.

Octets en Python

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

Les littéraux de chaîne sont décrits par les définitions lexicales suivantes:

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
la source
5

Vous devez le décoder pour le convertir en chaîne. Vérifiez la réponse ici à propos des octets littéraux 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
la source
1
le problème avec ceci est que, lorsque j'essaie de télécharger des tweets sans les encode("utf-8")erreurs, j'obtiens. Et, comme je l'ai mentionné ici, la suppression de stackoverflow.com/q/41915383/4422095 ne l'a pas résolue. Même si j'utilise le décodage comme vous le suggérez, j'obtiens toujours une erreur. Je publierai cela dans le post.
Stan Shunpike
terminé. ce n'est pas exactement la même chose car vous avez besoin des codes Twitter OAuth pour le faire. mais si vous faites simplement l'exemple que j'ai donné, vous aurez le même problème. il n'est pas résolu par la méthode suggérée. il annule juste l'utf-8. mais cela ne fonctionne pas car il ne traitera pas les caractères dans les tweets sans encodage utf-8
Stan Shunpike
Vous devez bien sûr utiliser un encodage correct. utf-8était un exemple.
salmanwahed le
4

**** Comment supprimer les caractères b '' qui est une chaîne décodée en python ****

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

Sur python 3.6 avec django 2.0, le décodage sur un littéral d'octet ne fonctionne pas comme prévu. Oui, j'obtiens le bon résultat lorsque je l'imprime, mais la valeur b est toujours là même si vous l'imprimez correctement.

C'est ce que j'encode

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

C'est ce que je décode:

uid = force_text(urlsafe_base64_decode(uidb64))

Voici ce que dit django 2.0:

urlsafe_base64_encode(s)[source]

Encode une chaîne d'octets en base64 pour une utilisation dans les URL, en supprimant tout signe égal à la fin.

urlsafe_base64_decode(s)[source]

Décode une chaîne encodée en base64, en rajoutant tout signe égal à la fin qui aurait pu être supprimé.


Ceci est mon fichier 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 %}

Voici ma réponse de console:

Content-Type: texte / brut; charset = "utf-8" Version MIME: 1.0 Content-Transfer-Encoding: 7bit Objet: Activez votre compte MySite De: webmaster @ localhost À: [email protected] Date: Ven, 20 Apr 2018 06:26:46 - 0000 ID de message: <152420560682.16725.4597194169307598579@Dash-U>

Salut testuser,

Veuillez cliquer sur le lien ci-dessous pour confirmer votre inscription:

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

comme vous pouvez le voir uid = b'MjU'

attendu uid = MjU


test dans la 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
>>> 

Après enquête, il semble que cela soit lié à python 3. Ma solution de contournement était assez simple:

'uid': user.pk,

je le reçois comme uidb64 sur ma fonction d'activation:

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

et 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/

maintenant cela fonctionne très bien. :)

Fernando D Jaime
la source
Je crois que le problème n'est pas le décodage, mais plutôt l'échappement automatique dans le modèle qui est incapable de séparer l'octet littéral en une chaîne, tout comme le fait le décodage.
Fernando D Jaime
1

Je l'ai fait en encodant uniquement la sortie en utilisant utf-8. Voici l'exemple de code

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)

c'est-à-dire: ne pas encoder lors de la collecte de données depuis l'API, encoder uniquement la sortie (impression ou écriture).

DevJoe
la source
0

En supposant que vous ne vouliez pas le décoder immédiatement comme d'autres le suggèrent ici, vous pouvez l'analyser en une chaîne, puis supprimer simplement le début 'bet la fin '.

>>> 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
la source
-2

Bien que la question soit très ancienne, je pense qu'elle peut être utile pour savoir qui est confronté au même problème. Ici, les textes sont une chaîne comme ci-dessous:

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

Ainsi, vous ne pouvez pas supprimer b en l'encodant car ce n'est pas un octet. J'ai fait ce qui suit pour le supprimer.

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

qui donnera "I posted a new photo to Facebook"

Kamol Roy
la source
3
Non, cela donnera "I posted a new photo to Facebook'". De toute façon, ce n’est pas de cela qu’il s’agit.
tripleee