Jak pozbyć się przedrostka b w ciągu znaków w Pythonie?

88

Wiele tweetów, które importuję, ma ten problem, gdy czytają

b'I posted a new photo to Facebook'

Zbieram b, że jest to bajt. Ale okazuje się to problematyczne, ponieważ w moich plikach CSV, które piszę, bnie znika i przeszkadza w przyszłym kodzie.

Czy istnieje prosty sposób na usunięcie tego bprzedrostka z moich wierszy tekstu?

Pamiętaj, że wydaje mi się, że muszę mieć tekst zakodowany w utf-8 lub tweepy ma problemy z wyciągnięciem ich z sieci.


Oto treść linku, który analizuję:

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

new_tweets = 'content in the link'

Próba kodu

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

Błąd

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
źródło
czy możesz pokazać przynajmniej część tych wierszy tekstu ?
RomanPerekhrest
@RomanPerekhrest Przepraszam, czego chciałbyś więcej? Kod czy wyjście?
Stan Shunpike
Zawsze określaj kodowanie podczas otwierania plików.
MKesper

Odpowiedzi:

136

trzeba zdekodowaćbytes z was chce ciąg:

b = b'1234'
print(b.decode('utf-8'))  # '1234'
bohater hiro
źródło
Zaktualizowałem pytanie. Myślę, że ta metoda nie działa. Jeśli tak, czy możesz wyjaśnić, dlaczego?
Stan Shunpike
4
.encode("utf-8").decode("utf-8")nie robi absolutnie nic (jeśli w ogóle działa) ... jesteś na Pythonie 3, prawda? py3 ma silne rozróżnienie między bytesa str. coś w twoim kodzie wydaje się używać cp1252kodowania ... możesz spróbować otworzyć plik za pomocą open(..., mode='w', encoding='utf-8')i tylko pisać strdo pliku; lub zapomnisz o całym kodowaniu i napisz plik binarnie: open(..., mode='wb')(zwróć uwagę na b) i pisz tylko bytes. To pomaga?
bohater hiro
Nie, to tego nie rozwiązuje. Dostałem"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
Jak możesz powiedzieć, że koduje jako cp1252? Ja też nie sądziłem, .encode("utf-8").decode("utf-8")że cokolwiek zrobię, ale ludzie tutaj wydawali się uważać, że to była właściwa odpowiedź, co nie jest tak daleko, jak widzę.
Stan Shunpike
Zauważyłem tę drogę w was traceback: C:\Users\Stan Shunpike\Anaconda3\lib\encodings\cp1252.py. prawdopodobnie powinieneś spróbować dowiedzieć się, jak / gdzie to jest używane. oh, i używasz csv.writer; w takim przypadku musisz napisać strrzeczywiście nie bytes. czy otrzymujesz rzeczy od requests? kodowanie otrzymane z zasobu internetowego może się różnić od utf-8.
bohater hiro
19

Po prostu informuje cię, że drukowany obiekt nie jest łańcuchem, a raczej obiektem bajtowym jako literałem bajtowym . Ludzie wyjaśniają to w niepełny sposób, więc oto moje podejście.

Rozważ utworzenie obiektu bajtowego poprzez wpisanie literału bajtowego (dosłowne zdefiniowanie obiektu bajtowego bez faktycznego używania obiektu bajtowego, np. Przez wpisanie b '') i przekonwertowanie go na obiekt łańcuchowy zakodowany w utf-8. (Zauważ, że konwersja oznacza tutaj dekodowanie )

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

Widzisz, że po prostu stosujemy tę .decode(utf8)funkcję.

Bajty w Pythonie

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

Literały ciągów są opisane za pomocą następujących definicji leksykalnych:

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
źródło
5

Musisz go zdekodować, aby przekonwertować go na ciąg. Sprawdź tutaj odpowiedź na temat literału bajtów w python3 .

In [1]: b'I posted a new photo to Facebook'.decode('utf-8')
Out[1]: 'I posted a new photo to Facebook'
salmanwahed
źródło
1
problem polega na tym, że kiedy próbuję pobrać tweety bez encode("utf-8")błędu, pojawiają się błędy. I, jak wspomniałem tutaj, usunięcie stackoverflow.com/q/41915383/4422095 nie rozwiązało problemu. Nawet jeśli używam dekodowania zgodnie z sugestią, nadal pojawia się błąd. Opublikuję to w poście.
Stan Shunpike
Gotowe. to nie jest dokładnie to samo, ponieważ potrzebujesz do tego kodów Twittera OAuth. ale jeśli zrobisz przykład, który podałem, pojawi się ten sam problem. nie rozwiązuje go metoda u sugerowana. po prostu cofa utf-8. ale to nie działa, ponieważ nie przetworzy znaków w tweetach bez kodowania utf-8
Stan Shunpike,
Oczywiście musisz użyć odpowiedniego kodowania. utf-8był przykładem.
salmanwahed
4

**** Jak usunąć znaki b '', które są dekodowanym ciągiem w Pythonie ****

import base64
a='cm9vdA=='
b=base64.b64decode(a).decode('utf-8')
print(b)
Avinash Chougule
źródło
2

W Pythonie 3.6 z django 2.0 dekodowanie literału bajtowego nie działa zgodnie z oczekiwaniami. Tak, otrzymuję właściwy wynik, gdy go drukuję, ale wartość b 'jest nadal obecna, nawet jeśli wydrukujesz ją poprawnie.

To właśnie je koduję

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

Oto, co im dekoduję:

uid = force_text(urlsafe_base64_decode(uidb64))

Oto, co mówi django 2.0:

urlsafe_base64_encode(s)[source]

Koduje bajtest w base64 do użycia w adresach URL, usuwając wszelkie końcowe znaki równości.

urlsafe_base64_decode(s)[source]

Dekoduje ciąg zakodowany w standardzie base64, dodając z powrotem wszystkie końcowe znaki równości, które mogły zostać usunięte.


To jest plik my 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 %}

Oto odpowiedź mojej konsoli:

Content-Type: tekst / zwykły; charset = "utf-8" Wersja MIME: 1.0 Content-Transfer-Encoding: 7bit Temat: Aktywuj swoje konto MySite Od: webmaster @ localhost Do: [email protected] Data: piątek, 20 kwietnia 2018 06:26:46 - 0000 Identyfikator wiadomości: <152420560682.16725.4597194169307598579@Dash-U>

Cześć użytkowniku,

Kliknij poniższy link, aby potwierdzić rejestrację:

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

jak widzisz uid = b'MjU'

spodziewany uid = MjU


test w konsoli:

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

Po zbadaniu wydaje się, że jest on powiązany z Pythonem 3. Moje obejście było dość proste:

'uid': user.pk,

otrzymuję go jako uidb64 w mojej funkcji aktywacji:

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

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

teraz działa dobrze. :)

Fernando D Jaime
źródło
Uważam, że problemem nie jest dekodowanie, ale wyłączenie autoescape w szablonie, który nie jest w stanie rozebrać literału bajtowego do ciągu, tak jak robi to dekodowanie.
Fernando D Jaime
1

Zrobiłem to, kodując tylko wyjście za pomocą utf-8. Oto przykład kodu

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)

tj .: nie koduj podczas zbierania danych z API, koduj tylko wyjście (drukuj lub zapisuj).

DevJoe
źródło
0

Zakładając, że nie chcesz od razu dekodować go ponownie, tak jak sugerują inni, możesz przeanalizować go na ciąg, a następnie po prostu usunąć początkowy 'bi końcowy '.

>>> 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
źródło
-2

Chociaż pytanie jest bardzo stare, myślę, że może być pomocne dla tego, kto ma ten sam problem. Tutaj teksty to ciąg jak poniżej:

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

Dlatego nie możesz usunąć b przez zakodowanie go, ponieważ nie jest to bajt. Wykonałem następujące czynności, aby go usunąć.

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

który da "I posted a new photo to Facebook"

Kamol Roy
źródło
3
Nie, to da "I posted a new photo to Facebook'". W każdym razie nie o to chodzi w tym pytaniu.
tripleee