Jak automatycznie wykryć kodowanie pliku tekstowego?

69

Istnieje wiele zwykłych plików tekstowych zakodowanych w różnych zestawach znaków.

Chcę przekonwertować je wszystkie na UTF-8, ale przed uruchomieniem iconv muszę znać jego oryginalne kodowanie. Większość przeglądarek ma Auto Detectopcję kodowania, jednak nie mogę sprawdzać tych plików tekstowych jeden po drugim, ponieważ jest ich zbyt wiele.

Znając tylko oryginalne kodowanie, mogę przekonwertować teksty iconv -f DETECTED_CHARSET -t utf-8.

Czy jest jakieś narzędzie do wykrywania kodowania zwykłych plików tekstowych? NIE musi być w 100% perfekcyjny, nie mam nic przeciwko, jeśli 100 milionów plików jest źle przekonwertowanych.

Xiè Jìléi
źródło

Odpowiedzi:

57

Wypróbuj chardetowy moduł Python, który jest dostępny na PyPi:

pip install chardet

Potem biegnij chardetect myfile.txt.

Chardet opiera się na kodzie wykrywania używanym przez Mozillę, więc powinien dawać rozsądne wyniki, pod warunkiem, że tekst wejściowy jest wystarczająco długi do analizy statystycznej. Przeczytaj dokumentację projektu .

Jak wspomniano w komentarzach, jest to dość powolne, ale niektóre dystrybucje dostarczają również oryginalną wersję C ++, którą @Xavier znalazł w https://superuser.com/a/609056 . Gdzieś jest też wersja Java.

grawitacji
źródło
3
Tak, i jest już zapakowany jak python-chardetw repozytorium wszechświata Ubuntu.
Xiè Jìléi
Jeśli to nie było idealne zgadywanie, chardetnadal daje najbardziej prawidłowe zgadywanie, jak ./a.txt: GB2312 (confidence: 0.99). W porównaniu do Enca, który właśnie zawiódł i zgłasza „Nierozpoznane kodowanie”. Niestety, chardetdziała bardzo wolno.
Xiè Jìléi
1
@ 谢 继 雷: Niech uruchomi się na noc lub coś takiego. Wykrywanie charset jest skomplikowany proces . Możesz także wypróbować jChardet oparty na Javie lub ... oryginalny chardet jest częścią Mozilli , ale dostępne jest tylko źródło C ++, bez narzędzia wiersza poleceń.
grawity
2
Jeśli chodzi o szybkość: bieganie chardet <(head -c4000 filename.txt)było znacznie szybsze i równie udane w moim przypadku użycia. (w przypadku, gdy nie jest jasne, ta składnia bash wyśle ​​tylko pierwsze 4000 bajtów do chardet)
ndemou
@ndemou Mam chardet==3.0.4, a rzeczywista nazwa pliku narzędzia wiersza polecenia chardetectnie jest chardet.
Devy,
31

Użyłbym tego prostego polecenia:

encoding=$(file -bi myfile.txt)

Lub jeśli chcesz tylko rzeczywisty zestaw znaków (jak utf-8):

encoding=$(file -b --mime-encoding myfile.txt)
Humpparitari
źródło
4
Niestety filewykrywa tylko kodowania o określonych właściwościach, takich jak UTF-8 lub UTF-16. Pozostałe - starsze ISO8859 lub ich odpowiedniki MS-DOS i Windows - są wymienione jako „nieznane - 8 bitów” lub coś podobnego, nawet w przypadku plików chardetwykrywanych z 99% pewnością.
grawity
6
plik pokazał mi iso-8859-1
cweiske
Co jeśli rozszerzenie leży?
james.garriss
2
@ james.garriss: rozszerzenie pliku nie ma nic wspólnego z jego (tekstowym) kodowaniem treści.
MestreLion
28

W systemie Linux opartym na Debianie pakiet uchardet ( Debian / Ubuntu ) zapewnia narzędzie wiersza poleceń. Zobacz opis opakowania poniżej:

 universal charset detection library - cli utility
 .
 uchardet is a C language binding of the original C++ implementation
 of the universal charset detection library by Mozilla.
 .
 uchardet is a encoding detector library, which takes a sequence of
 bytes in an unknown character encoding without any additional
 information, and attempts to determine the encoding of the text.
 .
 The original code of universalchardet is available at
 http://lxr.mozilla.org/seamonkey/source/extensions/universalchardet
 .
 Techniques used by universalchardet are described at
 http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html
Xavier
źródło
3
Dzięki! Ze strony głównej projektu nie było dla mnie oczywiste, że zawiera CLI. Jest również dostępny w systemie OS X podczas instalacji uchardetza pośrednictwem Homebrew.
Stefan Schmidt
1
Na początku byłem trochę zdezorientowany, ponieważ dokument ISO 8859-1 został fałszywie zidentyfikowany jako Windows-1252, ale w zakresie do wydrukowania Windows-1252 jest nadzbiorem ISO 8859-1, więc konwersja iconvdziała poprawnie.
Stefan Schmidt
16

W systemie Linux jest enca, aw systemie Solaris można użyć auto_ef .

cularis
źródło
Enca wydaje mi się zbyt surowa: enca -d -L zh ./a.txtkomunikat nie powiódł się ./a.txt: Unrecognized encoding Failure reason: No clear winner.Jak wspomniano w @grawity, chardetjest bardziej luźny, jednak jest zbyt wolny.
Xiè Jìléi
10
Enca kompletnie nie zdaje testu „faktycznie robi coś”.
Michael Wolf
1
uchardet nie powiódł się (wykrył CP1252 zamiast rzeczywistego CP1250), ale enca działał dobrze. (pojedynczy przykład, trudny do uogólnienia ...)
Palo,
2

Wracając do chardet (python 2.?) To wywołanie może wystarczyć:

python -c 'import chardet,sys; print chardet.detect(sys.stdin.read())' < file
{'confidence': 0.98999999999999999, 'encoding': 'utf-8'}

Chociaż to dalekie od ideału ...

echo "öasd" | iconv -t ISO-8859-1 | python -c 'import chardet,sys; print chardet.detect(sys.stdin.read())'
{'confidence': 0.5, 'encoding': 'windows-1252'}
estani
źródło
2

Dla tych, którzy regularnie używają Emacsa, mogą się przydać (pozwala to sprawdzić i ręcznie zweryfikować transfomację).

Ponadto często stwierdzam, że automatyczne wykrywanie zestawu znaków Emacsa jest znacznie wydajniejsze niż inne narzędzia do automatycznego wykrywania zestawu znaków (takie jak chardet).

(setq paths (mapcar 'file-truename '(
 "path/to/file1"
 "path/to/file2"
 "path/to/file3"
)))

(dolist (path paths)
  (find-file path)
  (set-buffer-file-coding-system 'utf-8-unix)
  )

Następnie wystarczy proste wywołanie Emacsa z tym skryptem jako argumentem (patrz opcja „-l”).

Yves Lhuillier
źródło
0

isutf8(z moreutilspaczki) wykonał zadanie

Ronan
źródło
2
W jaki sposób? Ta odpowiedź nie jest zbyt pomocna.
Mojżesz
1
Nie jest dokładnie pytany, ale jest użytecznym narzędziem. Jeśli plik jest poprawny UTF-8, kodem wyjścia jest zero. Jeśli plik nie jest prawidłowy UTF-8 lub wystąpił błąd, kod wyjścia jest różny od zera.
ton
0

Również w przypadku, gdy plik -i daje nieznane

Możesz użyć tego polecenia php, które może odgadnąć zestaw znaków, jak poniżej:

W php możesz sprawdzić jak poniżej:

Określając jawnie listę kodowania:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), 'UTF-8, ASCII, JIS, EUC-JP, SJIS, iso-8859-1') . PHP_EOL;"

Dokładniejsze „ mb_list_encodings ”:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), mb_list_encodings()) . PHP_EOL;"

Tutaj w pierwszym przykładzie widać, że umieściłem listę kodowań (wykryj kolejność list), które mogą być zgodne. Aby uzyskać dokładniejszy wynik, możesz użyć wszystkich możliwych kodowań poprzez: mb_list_encodings ()

Uwaga Funkcje mb_ * wymagają php-mbstring

apt-get install php-mbstring 

Zobacz odpowiedź: https://stackoverflow.com/a/57010566/3382822

Mohamed23gharbi
źródło