Konwertuj ciąg znaków Unicode na ciąg znaków w języku Python (zawierający dodatkowe symbole)

503

Jak przekonwertować ciąg Unicode (zawierający dodatkowe znaki, takie jak £ $ itp.) Na ciąg Python?

williamtroup
źródło
2
Musimy wiedzieć, jakiej wersji Python używasz i co to jest, że wywołujesz ciąg Unicode. Wykonaj następujące czynności na krótkim łańcuchu Unicode, który zawiera symbole waluty, które powodują problem : Python 2.x: print type(unicode_string), repr(unicode_string)Python 3.x: print type(unicode_string), ascii(unicode_string)Następnie edytuj pytanie i skopiuj / wklej wyniki powyższej instrukcji print. NIE wpisuj ponownie wyników. Spójrz również u góry HTML i sprawdź, czy możesz znaleźć coś takiego: <meta http-equiv = "Content-Type" content = "text / html; charset = iso-8859
John Machin
3
Wątpię, czy otrzymujesz Unicode z żądania sieci. Prawdopodobnie otrzymasz kodowanie UTF-8.
28
@lutz: jak dokładnie „Unicode kodowany w UTF-8” nie jest Unicode?
jalf
2
Powinieneś naprawdę wyjaśnić, co rozumiesz przez ciąg Unicode i ciąg Pythona (chyba konkretne przykłady byłyby najlepsze), ponieważ z komentarzy wynika, że ​​istnieją różne interpretacje twojego pytania. Zastanawiam się, dlaczego tego nie zrobiłeś, chociaż minęło ponad 3,5 roku, odkąd zadałeś to pytanie.
Piotr Dobrogost
6
@jalf: Jeśli jest zakodowany ; to już nie jest Unicode, np.unicode_string = u"I'm unicode string"; bytestring = unicode_string.encode('utf-8'); unicode_again = bytestring.decode('utf-8')
jfs

Odpowiedzi:

572

Widzieć unicodedata.normalize

title = u"Klüft skräms inför på fédéral électoral große"
import unicodedata
unicodedata.normalize('NFKD', title).encode('ascii', 'ignore')
'Kluft skrams infor pa federal electoral groe'
Sorantis
źródło
24
+1 odpowiedzi na pytanie sformułowane @ problemu williamtroup za nie jest w stanie uratować unicode do dźwięków plików jak zupełnie innej kwestii godnego osobnym pytaniu
Mark Roddy
5
@John - ta odpowiedź poprzedza wyjaśnienie PO.
Dominic Rodger
10
@Mark Roddy: Jego pytanie, jak napisano, brzmi: jak przekonwertować „ciąg znaków Unicode” (cokolwiek przez to rozumie) zawierający niektóre symbole walutowe na „ciąg znaków Pythona” (cokolwiek ...) i uważasz, że usuń niektóre znaki diakrytyczne usuń-inne-nie-ascii znaki kludge odpowiada na jego pytanie ???
John Machin
13
@JohnMachin To odpowiada na pytanie słowo w słowo: Jedynym sposobem na konwersję unicodeciągu na a strjest upuszczenie lub konwersja znaków, które nie mogą być reprezentowane w ASCII. Więc +1 ode mnie.
Izkata
4
@lzkata: nie, nie jest. type(title) == unicode and type(title.encode('utf-8')) == str. Nie ma potrzeby uszkadzania danych wejściowych, aby uzyskać bajtowanie, które można zapisać w pliku.
jfs
318

Możesz użyć kodowania na ASCII, jeśli nie musisz tłumaczyć znaków innych niż ASCII:

>>> a=u"aaaàçççñññ"
>>> type(a)
<type 'unicode'>
>>> a.encode('ascii','ignore')
'aaa'
>>> a.encode('ascii','replace')
'aaa???????'
>>>
Ferran
źródło
4
Świetna odpowiedź. Dokładnie to, czego potrzebowałem. Również świetna prezentacja, aby pokazać efekt ignorevsreplace
Jonny Brooks
lub a.encode('ascii', 'xmlcharrefreplace')daje 'aaa&#224;&#231;&#231;&#231;&#241;&#241;&#241;'.
Bob Stein,
type(a)jest strw Pythonie 3.6.8 i nie ma żadnej encode()metody.
Ali Tou
138
>>> text=u'abcd'
>>> str(text)
'abcd'

Jeśli ciąg zawiera tylko znaki ascii.

igco
źródło
18
Działa to tylko w systemie Windows. I pęknie, jeśli będą symbole nie-ascii.
Vanuan
6
Dzieje się tak, jeśli zawartość ciągu jest w rzeczywistości kodem Unicode, a nie tylko znakami ASCII w łańcuchu Unicode. Nie rób tego, otrzymasz losowe wyjątki UnicodeEncodeError w każdym miejscu.
Doug
11
Ta odpowiedź pomogła mi. Jeśli wiesz, że twój ciąg jest ascii i musisz rzucić go z powrotem na ciąg inny niż Unicode, jest to bardzo przydatne.
VedTopkar
113

Jeśli masz ciąg Unicode i chcesz zapisać go w pliku lub w innej postaci zserializowanej, musisz najpierw zakodować go w określonej reprezentacji, która może być przechowywana. Istnieje kilka typowych kodowań Unicode, takich jak UTF-16 (używa dwóch bajtów dla większości znaków Unicode) lub UTF-8 (1-4 bajty / punkt kodowy w zależności od znaku) itp. Aby przekonwertować ten ciąg na określone kodowanie, należy mogą korzystać:

>>> s= u'£10'
>>> s.encode('utf8')
'\xc2\x9c10'
>>> s.encode('utf16')
'\xff\xfe\x9c\x001\x000\x00'

Ten nieprzetworzony ciąg bajtów można zapisać do pliku. Pamiętaj jednak, że podczas odczytywania go ponownie musisz wiedzieć, w jakim jest kodowaniu i zdekodować go przy użyciu tego samego kodowania.

Pisząc do plików, możesz pozbyć się tego ręcznego procesu kodowania / dekodowania za pomocą modułu kodeków . Aby otworzyć plik, który koduje wszystkie ciągi Unicode w UTF-8 , użyj:

import codecs
f = codecs.open('path/to/file.txt','w','utf8')
f.write(my_unicode_string)  # Stored on disk as UTF-8

Pamiętaj, że wszystko, co korzysta z tych plików, musi zrozumieć, w jakim kodowaniu znajduje się plik, jeśli chce je odczytać. Jeśli tylko ty czytasz / piszesz, nie stanowi to problemu, w przeciwnym razie upewnij się, że piszesz w formie zrozumiałej dla innych osób korzystających z plików.

W Pythonie 3 ta forma dostępu do plików jest domyślna, a wbudowana openfunkcja pobiera parametr kodowania i zawsze tłumaczy na / z ciągów Unicode (domyślny obiekt ciągu w Pythonie 3) dla plików otwieranych w trybie tekstowym.

Brian
źródło
58

Oto przykład:

>>> u = u'€€€'
>>> s = u.encode('utf8')
>>> s
'\xe2\x82\xac\xe2\x82\xac\xe2\x82\xac'
Bastien Léonard
źródło
1
Czy ktoś może wyjaśnić, dlaczego, gdy koduję symbol Euro, utf8jak pokazano tutaj, wynikiem są tylko znaki zapytania? Oto obraz mojego Pythona, wersja 2.7.13. (Mogę zakodować inne obiekty Unicode, takie jak u"Klüft"euro, ale nie euro?)
The Red Pea
5

Cóż, jeśli chcesz / jesteś gotowy na przejście na Python 3 (co może nie wynikać z niezgodności wstecznej z niektórymi kodami Python 2), nie musisz wykonywać żadnej konwersji; cały tekst w Pythonie 3 jest reprezentowany przez ciągi Unicode, co oznacza również, że nie trzeba już używaću'<text>' składni. Masz również, w rzeczywistości, ciągi bajtów, które są używane do reprezentowania danych (które mogą być ciągami kodowanymi).

http://docs.python.org/3.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit

(Oczywiście, jeśli obecnie używasz języka Python 3, problem prawdopodobnie wiąże się ze sposobem zapisania tekstu w pliku).

UKŁUCIE
źródło
2
W Pythonie 3 ciągi znaków są ciągami Unicode. Nigdy nie są kodowane. Przydatny jest następujący tekst: joelonsoftware.com/articles/Unicode.html
Chce zapisać go do pliku; jak twoja odpowiedź na to pomaga?
John Machin
@lutz: Racja, zapomniałem, że Unicode to mapa znaków, a nie kodowanie. @John: W tej chwili nie ma wystarczających informacji, aby wiedzieć, na czym polega problem z ich zapisaniem. Czy dostaje błąd? Czy nie dostaje żadnych błędów, ale podczas otwierania pliku na zewnątrz dostaje mojibake? Bez tych informacji istnieje wiele możliwych rozwiązań.
JAB
@Cat: W tej chwili nie ma żadnych informacji, aby wiedzieć, co on ma, nie mówiąc już o jego problemie z oszczędzaniem. Poprosiłem go o podanie kilku faktów - zobacz moją odpowiedź.
John Machin
5

Oto przykładowy kod

import unicodedata    
raw_text = u"here $%6757 dfgdfg"
convert_text = unicodedata.normalize('NFKD', raw_text).encode('ascii','ignore')
Gihan Chathuranga
źródło
czym ta odpowiedź różni się od przyjętej odpowiedzi?
sgauri
3

plik zawiera ciąg znaków w formacie Unicode

\"message\": \"\\u0410\\u0432\\u0442\\u043e\\u0437\\u0430\\u0446\\u0438\\u044f .....\",

dla mnie

 f = open("56ad62-json.log", encoding="utf-8")
 qq=f.readline() 

 print(qq)                          
 {"log":\"message\": \"\\u0410\\u0432\\u0442\\u043e\\u0440\\u0438\\u0437\\u0430\\u0446\\u0438\\u044f \\u043f\\u043e\\u043b\\u044c\\u0437\\u043e\\u0432\\u0430\\u0442\\u0435\\u043b\\u044f\"}

(qq.encode().decode("unicode-escape").encode().decode("unicode-escape")) 
# '{"log":"message": "Авторизация пользователя"}\n'
madjardi
źródło
2
działało, nawet jeśli używam tylko:result.encode().decode('unicode-escape')
Ammad Khalid
0

Żadna odpowiedź nie zadziałała w moim przypadku, w którym miałem zmienną łańcuchową zawierającą znaki Unicode, a żadne wyjaśnione tutaj kodowanie-dekodowanie nie zadziałało.

Jeśli zrobię to w terminalu

echo "no me llama mucho la atenci\u00f3n"

lub

python3
>>> print("no me llama mucho la atenci\u00f3n")

Dane wyjściowe są poprawne:

output: no me llama mucho la atención

Ale praca ze skryptami ładującymi tę zmienną łańcuchową nie działała.

Oto, co zadziałało w mojej sprawie , na wypadek gdyby ktoś pomógł:

string_to_convert = "no me llama mucho la atenci\u00f3n"
print(json.dumps(json.loads(r'"%s"' % string_to_convert), ensure_ascii=False))
output: no me llama mucho la atención
pctripsesp
źródło
musisz zaimportować json
pctripsesp