Jak mogę zidentyfikować dziwną postać?

10

Próbuję zidentyfikować dziwną postać, którą znalazłem w pliku, z którym pracuję:

$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353  \n
0000002
$ od -x file
0000000 0aeb
0000002

Plik korzysta z kodowania ISO-8859 i nie można go przekonwertować na format UTF-8:

$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv  -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text

Moje główne pytanie brzmi: jak mogę zinterpretować wyniki odtutaj? Próbuję użyć tej strony, która pozwala mi tłumaczyć różne reprezentacje znaków, ale mówi mi, że 005353jako „punkt kodu Hex” wydaje się być niewłaściwy, a 0aebjako „punkt kodu Hex”, który ponownie wydaje się błędny .

Tak więc, w jaki sposób można zastosować jedną z trzech opcji ( 355, 005353lub 0aeb), aby dowiedzieć się, jaki charakter mają oni reprezentują?

I tak, próbowałem z narzędziami Unicode, ale nie wydaje się to być poprawnym znakiem UTF:

$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
    \pS \p{So}
    All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
       GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode

jeśli rozumiem opis znaku Unicode U + FFFD, to w ogóle nie jest to prawdziwy znak, ale symbol zastępczy dla uszkodzonego znaku. Ma to sens, ponieważ plik nie jest tak naprawdę zakodowany w UTF-8.

terdon
źródło
5
EB może być δ na stronie kodowej 437 lub ′ na stronie kodowej 850 lub ë w 8859-1 ; czy któryś z nich miałby sens? ( iconvnarzeka, ponieważ nie określiłeś źródłowego zestawu znaków, więc używa twojego domyślnego, którym jest prawdopodobnie UTF-8.)
Stephen Kitt
@StephenKitt tak, ëwłaśnie to widzę, gdy dane są wykorzystywane w innym programie! Ale skąd mam to wiedzieć? Czy nie jest to gdzieś w danych, które podaję? Jak to znalazłeś? Aha próbowałem iconvze -f ISO-8859jednak skarżył conversion from ISO-8859' nie jest wspierani.
terdon
1
Argh! Rozumiem, musiałem użyć tylko ebi zignorować 0xwskaźnik heksadecymalny lub cokolwiek to jest. Moja nieznajomość tego rodzaju rzeczy jest głęboka. Czy możesz opublikować odpowiedź wyjaśniającą, że @StephenKitt?
terdon
5
Twoim zasadniczym błędem jest to, że ISO-8859 nie jest nazwą kodowania. To rodzina kodowań; najwyraźniej tym, którego szukasz, jest ISO-8859-1.
tripleee
1
Wtedy twój iconvby się udało; i / lub mogłeś to sprawdzić np. na Wikipedii. W przypadku tego bardzo specyficznego kodowania działa również fileformat.info/info/unicode/char/00eb/index.htm (Unicode odpowiada ISO-8859-1 w zakresie 128-255, choć oczywiście żadne kodowanie UTF nie jest z nim zgodne ).
tripleee

Odpowiedzi:

22

Twój plik zawiera dwa bajty, EB i 0A w trybie szesnastkowym. Prawdopodobnie plik używa zestawu znaków z jednym bajtem na znak, na przykład ISO-8859-1 ; w tym zestawie znaków EB jest ë:

$ printf "\353\n" | iconv -f ISO-8859-1
ë

Inni kandydaci byliby δ na stronie kodowej 437 , Ù na stronie kodowej 850 ...

od -xwyniki są w tym przypadku mylące z powodu endianizmu; lepszym rozwiązaniem jest -t x1użycie pojedynczych bajtów:

$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002

od -xmapy, do od -t x2których odczytuje dwa bajty naraz, a w systemach little-endian wysyła bajty w odwrotnej kolejności.

Gdy natrafisz na taki plik, który nie jest prawidłowy UTF-8 (lub nie ma sensu, gdy jest interpretowany jako plik UTF-8), nie ma niezawodnego sposobu automatycznego określenia jego kodowania (i zestawu znaków). Kontekst może pomóc: jeśli jest to plik wyprodukowany na zachodnim komputerze w ciągu ostatnich kilku dekad, istnieje spora szansa, że ​​jest zakodowany w ISO-8859-1, -15 (wariant Euro) lub Windows-1252; jeśli jest starszy, CP-437 i CP-850 są prawdopodobnie kandydatami. Pliki z systemów wschodnioeuropejskich, rosyjskich lub azjatyckich używałyby różnych zestawów znaków, o których niewiele wiem. Potem jest EBCDIC ... iconv -lwyświetli listę wszystkich zestawów znaków, iconvo których wie, i możesz zacząć od próby i błędu.

(W pewnym momencie znałem większość CP-437 i ATASCII na pamięć, były to dni).

Stephen Kitt
źródło
1
OK, na stronie wikipedii, do której linkujesz, widzę, że ëjest to opisane jako 00EBi 234. Co to są dodatkowe 00? I dlaczego nie jest tak, 355jak się spodziewałem po odwynikach? Próbuję uzyskać bardziej ogólną odpowiedź na temat tego, w jaki sposób mogę wykorzystać dane odwyjściowe do zidentyfikowania postaci. Czy możesz wyjaśnić coś na temat interpretacji kodów szesnastkowych i / lub jakie informacje są potrzebne, aby móc zidentyfikować nieznany znak (kodowanie i cokolwiek innego)?
terdon
EB wynosi 353 ósemkowo (nie 355). Spróbuję uogólnić ...
Stephen Kitt
Ups, przepraszam, miałem na myśli 353. Tak więc 353 jest reprezentacją ósemkową, a nie dziesiętną. Argh.
terdon
1
Tak, „o” odoznacza ósemkę ;-).
Stephen Kitt
1
W każdym razie (U + FFFD) byłby wyświetlany przez emulator terminala jako zamiennik tego bajtu 0xeb, który nie tworzy prawidłowego znaku w UTF-8. Nie jest jasne, dlaczego uniprops $(cat file)(brakujące cytaty btw) miałoby to zgłosić (nie wiem o tym unipropspoleceniu). unicode "$(cat file)"na Debianie wykonuje dane wyjściowe Sequence '\xeb' is not valid in charset 'UTF-8'zgodnie z oczekiwaniami.
Stéphane Chazelas
5

Zauważ, że odjest skrótem od ósemkowego zrzutu , więc 005353dwa bajty jako ósemkowe słowo, od -x0aebszesnastkowe jak słowo, a rzeczywista zawartość twojego pliku to dwa bajty ebi 0aszesnastkowo, w tej kolejności.

Więc obie 005353i 0aebnie można po prostu być interpretowane jako „punkt kodu hex”.

0ajest linią (LF) i ebzależy od twojego kodowania. filetylko zgaduje kodowanie, może to być cokolwiek. Bez dalszych informacji, skąd pochodzi plik itp., Będzie trudno go znaleźć.

reż
źródło
Zdaję sobie sprawę, że dzieje się tak, ponieważ nie rozumiem, jak działają punkty kodowe (lub szesnastkowe, naprawdę), ale skąd mam to wiedzieć? Zwykle używam, od -cponieważ daje to wynik, który mogę zrozumieć. Jak mogłem użyć 355produkujących do identyfikacji postaci? I dlaczego drukuje 0aebzamiast eb0aczy 0anowa linia?
terdon
@terdon endianness ... Zobacz moją zaktualizowaną odpowiedź.
Stephen Kitt
2

Niemożliwe jest odgadnięcie ze 100% dokładnością zestawu plików tekstowych.

Narzędzia takie jak chardet , firefox , plik -i, gdy nie ma zdefiniowanych jawnych informacji o zestawie znaków (np. Jeśli HTML zawiera meta zestaw znaków = ... w głowie, rzeczy są łatwiejsze) spróbują użyć heurystyki, która nie jest taka zła, jeśli tekst jest wystarczająco duży.

Poniżej demonstruję wykrywanie zestawów znaków za pomocą chardet( pip install chardet/ apt-get install python-chardetjeśli to konieczne).

$ echo "in Noël" | iconv -f utf8 -t latin1  | chardet
<stdin>: windows-1252 with confidence 0.73

Po dobrym charset kandydata, możemy użyć iconv, recodelub podobna do zmiany kodowania pliku do „aktywnego” zestawu znaków (w moim przypadku UTF-8) i sprawdzić, czy jest prawidłowo odgadł ...

iconv -f windows-1252  -t utf-8 file

Niektóre zestawy znaków (takie jak iso-8859-3, iso-8859-1) mają wiele wspólnych znaków - czasem nie jest łatwo sprawdzić, czy znaleźliśmy idealny zestaw znaków ...

Dlatego bardzo ważne jest, aby metadane były powiązane z odpowiednim tekstem (np. XML).

JJoao
źródło
Hmm Nie mogę go tutaj odtworzyć, po prostu ulega awarii. Ale czy tak nie jest, czy to po prostu mówi mi o kodowaniu pliku? Moim problemem jest identyfikacja znaku, a nie kodowanie pliku. To już wiedziałem.
terdon
1
Przepraszamy, nie zrozumiałem pytania (moim zwykłym problemem jest identyfikacja zestawu znaków). jeśli teraz kodujesz, iconv -f ... -t utf-8 pokaże ci znaki?
JJoao
Nie. Pokazuję kodowanie właśnie tam. Był jeden konkretny znak nieobsługiwany przez to kodowanie i to ten znak, który próbowałem zidentyfikować.
terdon
1
ISO-8859 nie jest kodowaniem! kodowanie jest iso-8850-1. iso-8859 jest standardem iso, zawierającym kilka definicji chasetów. Spróbujfile -i ...
JJoao 28.04.17
1
@terdon, przykro mi nalegać, ale wszystkie sztuczki, które próbowałeś, pracowały z właściwym zestawem znaków. Np .: iconv -f ISO-8859-1 -t UTF-8 file
JJoao
0
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//') 
do 
    iconv -f $enc -t UTF-8 $FILE  2>/dev/null | grep -m 1 $PATTERN && echo $enc 
done 

Jeśli otrzymam plik, który zawiera na przykład słowo Begrung, mogę wywnioskować, że Begrüßung mógł mieć na myśli. Konwertuję go więc za pomocą wszystkich znanych kodowań i sprawdzam, czy ktoś go znajdzie, co poprawnie konwertuje.

Zwykle istnieje wiele kodowań, które wydają się pasować.

W przypadku dłuższych plików możesz wyciąć fragment kodu zamiast konwertować setki stron.

Więc nazwałbym to

encodingfinder.sh FILE Begrüßung

i testy skryptów, czy konwertując je ze znanymi kodowaniami, które z nich produkują „Begrüßung”.

Aby znaleźć takie postacie, zwykle pomaga mniej, ponieważ postacie funky często się wyróżniają. Z kontekstu można zazwyczaj wywnioskować właściwe słowo do wyszukania. Ale nie chcemy sprawdzać za pomocą hekseditora, jaki to bajt, a następnie odwiedzać niekończące się tabele kodowania, aby znaleźć naszego przestępcę. :)

nieznany użytkownik
źródło