u '\ ufeff' w ciągu znaków Pythona

153

Otrzymuję błąd z następującym wzorcem:

UnicodeEncodeError: 'ascii' codec can't encode character u'\ufeff' in position 155: ordinal not in range(128)

Nie wiem, co to u'\ufeff'jest, pojawia się, gdy przeglądam sieć. Jak mogę zaradzić tej sytuacji? Metoda .replace()string na tym nie działa.

James Hallen
źródło
6
Skąd pochodzą te dane wejściowe? Co próbujesz zrobić? Dołącz swój kod w Pythonie.
7
Nawiasem mówiąc, stwierdzam, że .replace () działa we współczesnym Pythonie, jeśli pamiętam wskaźnik Unicode: s.replace (u '\ ufeff', '')
Doug Bradshaw
@DougBradshaw, kiedy mówisz „nowoczesny Python”, masz na myśli 2.7+ czy 3.0+?
teewuane
Słuszna uwaga. Czyli 2.7+.
Doug Bradshaw

Odpowiedzi:

184

Znak Unicode U+FEFFjest znacznikiem kolejności bajtów lub BOM i służy do określania różnicy między kodowaniem big- i little-endian UTF-16. Jeśli zdekodujesz stronę internetową przy użyciu odpowiedniego kodeka, Python usunie ją za Ciebie. Przykłady:

#!python2
#coding: utf8
u = u'ABC'
e8 = u.encode('utf-8')        # encode without BOM
e8s = u.encode('utf-8-sig')   # encode with BOM
e16 = u.encode('utf-16')      # encode with BOM
e16le = u.encode('utf-16le')  # encode without BOM
e16be = u.encode('utf-16be')  # encode without BOM
print 'utf-8     %r' % e8
print 'utf-8-sig %r' % e8s
print 'utf-16    %r' % e16
print 'utf-16le  %r' % e16le
print 'utf-16be  %r' % e16be
print
print 'utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8')
print 'utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig')
print 'utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16')
print 'utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le')

Zwróć uwagę, że EF BB BFjest to BOM zakodowany w UTF-8. Nie jest wymagany dla UTF-8, ale służy tylko jako podpis (zwykle w systemie Windows).

Wynik:

utf-8     'ABC'
utf-8-sig '\xef\xbb\xbfABC'
utf-16    '\xff\xfeA\x00B\x00C\x00'    # Adds BOM and encodes using native processor endian-ness.
utf-16le  'A\x00B\x00C\x00'
utf-16be  '\x00A\x00B\x00C'

utf-8  w/ BOM decoded with utf-8     u'\ufeffABC'    # doesn't remove BOM if present.
utf-8  w/ BOM decoded with utf-8-sig u'ABC'          # removes BOM if present.
utf-16 w/ BOM decoded with utf-16    u'ABC'          # *requires* BOM to be present.
utf-16 w/ BOM decoded with utf-16le  u'\ufeffABC'    # doesn't remove BOM if present.

Zwróć uwagę, że utf-16kodek wymaga obecności BOM, w przeciwnym razie Python nie będzie wiedział, czy dane są typu big- czy little-endian.

Mark Tolonen
źródło
201

Natknąłem się na to w Pythonie 3 i znalazłem to pytanie (i rozwiązanie ). Podczas otwierania pliku Python 3 obsługuje słowo kluczowe encoding, aby automatycznie obsługiwać kodowanie.

Bez tego zestawienie komponentów jest uwzględniane w wyniku odczytu:

>>> f = open('file', mode='r')
>>> f.read()
'\ufefftest'

Podając prawidłowe kodowanie, BOM jest pomijany w wyniku:

>>> f = open('file', mode='r', encoding='utf-8-sig')
>>> f.read()
'test'

Tylko moje 2 centy.

siebz0r
źródło
13
Dziękuję, to jest rzeczywiste rozwiązanie i powinno być zaakceptowaną odpowiedzią. Chociaż to jest wielki wgląd dlaczego ciąg jest tam większość osób przybywających tu szuka proste rozwiązanie i to jest to.
neurino
3
Miałem ten sam problem z csv DictReader odczytującym plik csv zapisany z Excela.
LArntz
1
Tak, Excel (nawet „csv” wygenerowany przez Excel) to naprawdę gorący bałagan.
rybołów
4

Tym znakiem jest BOM lub „Byte Order Mark”. Zwykle jest odbierany jako kilka pierwszych bajtów pliku, informując Cię, jak interpretować kodowanie pozostałych danych. Możesz po prostu usunąć znak, aby kontynuować. Chociaż, ponieważ błąd mówi, że próbujesz przekonwertować na „ascii”, prawdopodobnie powinieneś wybrać inne kodowanie dla tego, co próbujesz zrobić.

swstephe
źródło
4

Treść, którą skrobasz, jest zakodowana w Unicode, a nie w tekście ascii, i otrzymujesz znak, który nie jest konwertowany na ascii. Właściwe „tłumaczenie” zależy od tego, co uważała za oryginalną stronę internetową. Strona Unicode w Pythonie zawiera informacje o tym, jak to działa.

Próbujesz wydrukować wynik lub umieścić go w pliku? Błąd sugeruje, że zapisuje dane, które powodują problem, a nie je odczytuje. To pytanie jest dobrym miejscem do szukania poprawek.

teodoks
źródło
0

Tutaj opiera się na odpowiedzi Marka Tolonena. Ciąg zawierał różne języki słowa „test”, które jest oddzielone znakiem „|”, więc widać różnicę.

u = u'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
e8 = u.encode('utf-8')        # encode without BOM
e8s = u.encode('utf-8-sig')   # encode with BOM
e16 = u.encode('utf-16')      # encode with BOM
e16le = u.encode('utf-16le')  # encode without BOM
e16be = u.encode('utf-16be')  # encode without BOM
print('utf-8     %r' % e8)
print('utf-8-sig %r' % e8s)
print('utf-16    %r' % e16)
print('utf-16le  %r' % e16le)
print('utf-16be  %r' % e16be)
print()
print('utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8'))
print('utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig'))
print('utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16'))
print('utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le'))

Oto przebieg próbny:

>>> u = u'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> e8 = u.encode('utf-8')        # encode without BOM
>>> e8s = u.encode('utf-8-sig')   # encode with BOM
>>> e16 = u.encode('utf-16')      # encode with BOM
>>> e16le = u.encode('utf-16le')  # encode without BOM
>>> e16be = u.encode('utf-16be')  # encode without BOM
>>> print('utf-8     %r' % e8)
utf-8     b'ABCtest\xce\xb2\xe8\xb2\x9d\xe5\xa1\x94\xec\x9c\x84m\xc3\xa1sb\xc3\xaata|test|\xd8\xa7\xd8\xae\xd8\xaa\xd8\xa8\xd8\xa7\xd8\xb1|\xe6\xb5\x8b\xe8\xaf\x95|\xe6\xb8\xac\xe8\xa9\xa6|\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88|\xe0\xa4\xaa\xe0\xa4\xb0\xe0\xa5\x80\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb7\xe0\xa4\xbe|\xe0\xb4\xaa\xe0\xb4\xb0\xe0\xb4\xbf\xe0\xb4\xb6\xe0\xb5\x8b\xe0\xb4\xa7\xe0\xb4\xa8|\xd7\xa4\xd6\xbc\xd7\xa8\xd7\x95\xd7\x91\xd7\x99\xd7\xa8\xd7\x9f|ki\xe1\xbb\x83m tra|\xc3\x96l\xc3\xa7ek|'
>>> print('utf-8-sig %r' % e8s)
utf-8-sig b'\xef\xbb\xbfABCtest\xce\xb2\xe8\xb2\x9d\xe5\xa1\x94\xec\x9c\x84m\xc3\xa1sb\xc3\xaata|test|\xd8\xa7\xd8\xae\xd8\xaa\xd8\xa8\xd8\xa7\xd8\xb1|\xe6\xb5\x8b\xe8\xaf\x95|\xe6\xb8\xac\xe8\xa9\xa6|\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88|\xe0\xa4\xaa\xe0\xa4\xb0\xe0\xa5\x80\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb7\xe0\xa4\xbe|\xe0\xb4\xaa\xe0\xb4\xb0\xe0\xb4\xbf\xe0\xb4\xb6\xe0\xb5\x8b\xe0\xb4\xa7\xe0\xb4\xa8|\xd7\xa4\xd6\xbc\xd7\xa8\xd7\x95\xd7\x91\xd7\x99\xd7\xa8\xd7\x9f|ki\xe1\xbb\x83m tra|\xc3\x96l\xc3\xa7ek|'
>>> print('utf-16    %r' % e16)
utf-16    b"\xff\xfeA\x00B\x00C\x00t\x00e\x00s\x00t\x00\xb2\x03\x9d\x8cTX\x04\xc7m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x00'\x06.\x06*\x06(\x06'\x061\x06|\x00Km\xd5\x8b|\x00,nf\x8a|\x00\xc60\xb90\xc80|\x00*\t0\t@\t\x15\tM\t7\t>\t|\x00*\r0\r?\r6\rK\r'\r(\r|\x00\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x05|\x00k\x00i\x00\xc3\x1em\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|\x00"
>>> print('utf-16le  %r' % e16le)
utf-16le  b"A\x00B\x00C\x00t\x00e\x00s\x00t\x00\xb2\x03\x9d\x8cTX\x04\xc7m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x00'\x06.\x06*\x06(\x06'\x061\x06|\x00Km\xd5\x8b|\x00,nf\x8a|\x00\xc60\xb90\xc80|\x00*\t0\t@\t\x15\tM\t7\t>\t|\x00*\r0\r?\r6\rK\r'\r(\r|\x00\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x05|\x00k\x00i\x00\xc3\x1em\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|\x00"
>>> print('utf-16be  %r' % e16be)
utf-16be  b"\x00A\x00B\x00C\x00t\x00e\x00s\x00t\x03\xb2\x8c\x9dXT\xc7\x04\x00m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x06'\x06.\x06*\x06(\x06'\x061\x00|mK\x8b\xd5\x00|n,\x8af\x00|0\xc60\xb90\xc8\x00|\t*\t0\t@\t\x15\tM\t7\t>\x00|\r*\r0\r?\r6\rK\r'\r(\x00|\x05\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x00|\x00k\x00i\x1e\xc3\x00m\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|"
>>> print()

>>> print('utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8'))
utf-8  w/ BOM decoded with utf-8     '\ufeffABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig'))
utf-8  w/ BOM decoded with utf-8-sig 'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16'))
utf-16 w/ BOM decoded with utf-16    'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le'))
utf-16 w/ BOM decoded with utf-16le  '\ufeffABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'

Warto wiedzieć, że tylko oba utf-8-sigi utf-16odzyskać oryginalny ciąg po obu encodei decode.

caot
źródło
-3

Ten problem pojawia się w zasadzie, gdy zapisujesz kod Pythona w kodowaniu UTF-8 lub UTF-16, ponieważ python automatycznie dodaje jakiś znak specjalny na początku kodu (który nie jest wyświetlany przez edytory tekstu) w celu zidentyfikowania formatu kodowania. Ale kiedy próbujesz wykonać kod, wyświetla błąd składni w linii 1, tj. Początek kodu, ponieważ kompilator Pythona rozumie kodowanie ASCII . kiedy przeglądasz kod pliku za pomocą funkcji read () , możesz zobaczyć na początku zwracanego kodu '\ ufeff' . Najprostszym rozwiązaniem tego problemu jest po prostu zmiana kodowania z powrotem na kodowanie ASCII (w tym celu możesz skopiować kod do notatnika i zapisać go Pamiętaj! wybierz kodowanie ASCII ... Nadzieja to pomoże.

Jagdish Chauhan
źródło