Znalazłem rozwiązanie na podobne pytanie na inny temat, ale niestety u mnie nie działa. Oto mój problem:
Tworzę ramkę danych z unicodes par zastępczych, które chciałbym wyszukać w innym pliku (na przykład: „\ uD83C \ uDFF3”, „\ u26F9”, „\ uD83C \ uDDE6 \ uD83C \ uDDE8”):
with open("unicodes.csv", "rt") as csvfile:
emoticons = pd.read_csv(csvfile, names=["xy"])
emoticons = pd.DataFrame(emoticons)
emoticons = emoticons.astype(str)
Następnie czytam mój plik z tekstem, w którym niektóre wiersze zawierają zastępcze pary unicodes:
for chunk in pd.read_csv(path, names=["xy"], encoding="utf-8", chunksize=chunksize):
spam = pd.DataFrame(chunk)
spam = spam.astype(str)
W tej pętli for sprawdzam, czy wiersz zawiera surogatepairs unicode, a jeśli to prawda, to chciałbym wydrukować tę surogatepair unicode jako emoji - dlatego koduję i dekoduję tę wartość "i", która jest str: (rozwiązanie z: Jak pracować z parami zastępczymi w Pythonie?)
for i in emoticons.xy:
if spam["xy"].str.contains(i, regex=False).any():
print(i.encode('utf-16', 'surrogatepass').decode('utf-16'))
#printing:
#\uD83C\uDFF3
#\u26F9
#\uD83C\uDDE6\uD83C\uDDE8
Tak więc, kiedy uruchamiam program, nadal drukuje on pary zastępcze unicode jako str, a nie jako emoji, ale kiedy samodzielnie wprowadzam unicode pary zastępczej do funkcji drukowania, działa:
print("\uD83C\uDFF3".encode("utf-16", "surrogatepass").decode("utf-16", "surrogatepass"))
#printing:
#🏳
Co ja robię źle? Próbowałem utworzyć ciąg z tego i innych rozwiązań, ale nadal nie działa.
EDYTOWAĆ:
hexdump -C file.csv
00004b70 5c 75 44 38 33 44 5c 75 44 45 45 39 0a 5c 75 44 |\uD83D\uDEE9.\uD|
00004b80 38 33 44 5c 75 44 45 45 42 0a 5c 75 44 38 33 44 |83D\uDEEB.\uD83D|
00004b90 5c 75 44 45 45 43 0a 5c 75 44 38 33 44 5c 75 44 |\uDEEC.\uD83D\uD|
00004ba0 43 42 41 0a 5c 75 44 38 33 44 5c 75 44 45 38 31 |CBA.\uD83D\uDE81|
EDYCJA2: Więc znalazłem coś, co działa, ale nadal potrzebuję poprawy: https://stackoverflow.com/a/54918256/4789281
Tekst z mojego innego pliku, który chcę przekonwertować plik wygląda:
"O żółtku zapomniałaś \uD83D\uDE02"
"Piękny outfit \uD83D\uDE0D"
Kiedy robię to, co było zalecane w innym temacie:
print(codecs.decode(i,encoding='unicode_escape',errors='surrogateescape').encode('utf-16', 'surrogatepass').decode('utf-16'))
Mam coś takiego:
O żóÅtku zapomniaÅaÅ 😂
PiÄkny outfit 😍
Więc moje zastępcze pary są zastępowane, ale moje polskie znaki są zastępowane czymś dziwnym.
1 odpowiedź
Jesteś na dobrej drodze. To, co próbujesz zrobić, jest przerywane, ponieważ to, co masz w swoim "str" po przeczytaniu pliku, nie jest "parami zastępczymi" - zamiast tego są zakodowanymi odwrotnymi ukośnikami punktami kodowymi dla twoich par zastępczych, zakodowanymi jako tekst.
To znaczy: sekwencja „5c 75 44 38 33 44” w twoim pliku to RZECZYWISTE znaki ascii „\uD83D” (w sumie 6 znaków), a nie zastępczy punkt kodowy 0xD83D (który po prawidłowym zdekodowaniu wraz z następnym zastępczym kodem „ \uDE0D” będzie pojedynczym znakiem w ciągu).
Część, o której powiedziałem, że jesteś na dobrej drodze, to: naprawdę musisz zakodować to w sekwencję bajtów, a następnie odkodować ją z powrotem. Błędem jest to, że musisz zakodować go za pomocą "latin1" (tylko po to, aby spróbować zachować dowolny inny znak spoza ascii, który masz w ciągu - może się on zepsuć, jeśli masz punkty kodowe, których nie można przedstawić w języku łacińskim1), i zdekoduj go z powrotem za pomocą specjalny kodek „unicode escape”. lub kodowanie charmap, które zachowuje twoje inne znaki w łańcuchu, a następnie dekoduje je z powrotem, używając tego samego kodeka. W tym momencie oba znaki zastępcze będą tekstem jako dwa znaki w łańcuchu Pythona:
In [16]: "\\uD83D\\uDE0D".encode("latin1").decode("unicode escape", "surrogatepass")
Out[16]: '\ud83d\ude0d'
Zła wiadomość jest taka - to nie jest bardzo poprawna STR - znaki zastępcze nie powinny istnieć same w wewnętrznej reprezentacji - zamiast tego powinny być połączone w pożądany końcowy znak. Tak więc próba wydrukowania tego zepsuje:
In [19]: a = "\\uD83D\\uDE0D".encode("utf-8").decode("unicode escape")
In [20]: print(a)
---------------------------------------------------------------------------
UnicodeEncodeError Traceback (most recent call last)
<ipython-input-20-bca0e2660b9f> in <module>
----> 1 print(a)
UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed
Użycie tutaj polityki błędów "surrogatepass" nie pomoże - otrzymasz niedrukowalną sekwencję bajtów.
Dlatego po raz drugi musi to zostać "zakodowane" i "odszyfrowane" - tym razem znaki, które masz w tekście, są rzeczywistymi "zastępczymi" punktami kodowymi, które byłyby prawidłowym kodem UTF-16 do zdekodowania. Tak więc ścieżką jest teraz zakodowanie tej sekwencji, brutalne wymuszenie tych znaków za pomocą „surogatepass”, a następnie dekodowanie z powrotem z utf-16 – co w końcu zrozumie parę zastępczą jako pojedynczy znak:
In [30]: a = "\\uD83D\\uDE0D".encode("unicode escape").decode("unicode escape")
In [31]: a
Out[31]: '\ud83d\ude0d'
In [32]: b = a.encode("utf-16", "surrogatepass").decode("utf-16")
In [33]: print(b)
😍
Podsumowanie:
Czytasz swój plik jako tekst utf-8, aby odczytać możliwe inne znaki spoza ASCII, zakoduj wynik jako „ucieczkę unicode” i odkoduj go z powrotem - to przekonwertuje rozszerzone sekwencje „\uXXXX” czytelne dla człowieka w twoim pliku jako zastępcze punkty kodowe. Następnie konwertujesz go z powrotem do utf-16, mówiąc Pythonowi, aby zignorował surogaty i skopiował następnie "tak jak jest" i dekodował z powrotem z utf-16:
def decode_surrogate_ascii(txt):
interm = txt.encode("latin1").decode("unicode escape")
return interm.encode("utf-16", "surrogatepass").decode("utf-16")
Wszystko, co musisz zrobić, to zastosować powyższą funkcję w interesujących kolumnach w ramce danych:
emoticons = emoticons.apply(pd.Series(lambda row: (decode_surrogate_ascii(item) if isinstance(item, str) else item for item in row ))
Podobne pytania
Powiązane pytania
Nowe pytania
python-3.x
W przypadku pytań dotyczących programowania w języku Python, które są specyficzne dla wersji 3+ tego języka. Użyj bardziej ogólnego tagu [python] we wszystkich pytaniach Pythona i dodaj ten tylko, jeśli twoje pytanie dotyczy wersji. Użyj znaczników [python-2.x] w pytaniach o Python 2.
"\uD83C\uDFF3"
jest poprawnie reprezentowane jako'\U0001f3f3'
. Jeśli jednak masz dane zserializowane jako (nieprawidłowe) UTF-8 z surogatami i nie możesz naprawić źródła, to podaj to wyraźnie (np. pokaż fragment zrzutu szesnastkowego takiego regionu w dokumencie wejściowym).` (backslash),
u,
D,
8,
3,
D` itd. Czy są przypadkiem osadzone fragmenty JSON w pliku CSV ? Ponieważ JSON używa tej notacji do ucieczki znaków spoza zestawu ASCII i koduje znaki powyżej U + FFFF z zastępczymi kodami ucieczki.