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.

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.


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)

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

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 .


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'}

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”).




0

isutf8(z moreutilspaczki) wykonał zadanie


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.