W odniesieniu do następującego wątku: Aplikacja Java: Nie można poprawnie odczytać pliku zakodowanego w standardzie iso-8859-1
Jaki jest najlepszy sposób programowego określenia prawidłowego kodowania zestawu znaków strumienia wejściowego / pliku?
Próbowałem użyć następujących:
File in = new File(args[0]);
InputStreamReader r = new InputStreamReader(new FileInputStream(in));
System.out.println(r.getEncoding());
Ale w przypadku pliku, o którym wiem, że jest zakodowany za pomocą ISO8859_1, powyższy kod daje ASCII, co nie jest poprawne i nie pozwala mi poprawnie wyrenderować zawartości pliku z powrotem na konsolę.
Reader.getEncoding
zwraca kodowanie, którego używał czytnik, które w twoim przypadku jest kodowaniem domyślnym.Odpowiedzi:
Użyłem tej biblioteki, podobnej do jchardet do wykrywania kodowania w Javie: http://code.google.com/p/juniversalchardet/
źródło
Nie można określić kodowania dowolnego strumienia bajtów. Taka jest natura kodowania. Kodowanie oznacza mapowanie między wartością bajtu a jej reprezentacją. Zatem każde kodowanie „mogłoby” być właściwe.
Metoda getEncoding () zwróci kodowanie, które zostało ustawione (przeczytaj JavaDoc ) dla strumienia. Nie będzie odgadnąć kodowania za Ciebie.
Niektóre strumienie informują, jakie kodowanie zostało użyte do ich utworzenia: XML, HTML. Ale nie jest to dowolny strumień bajtów.
W każdym razie możesz spróbować samodzielnie odgadnąć kodowanie, jeśli musisz. Każdy język ma wspólną częstotliwość dla każdego znaku. W języku angielskim char e pojawia się bardzo często, ale ê pojawia się bardzo rzadko. W strumieniu ISO-8859-1 zwykle nie ma znaków 0x00. Ale strumień UTF-16 ma ich dużo.
Lub: możesz zapytać użytkownika. Widziałem już aplikacje, które przedstawiają fragment pliku w różnych kodowaniach i proszą o wybranie „właściwego”.
źródło
sprawdź to: http://site.icu-project.org/ (icu4j) mają biblioteki do wykrywania zestawu znaków z IOStream może być takie proste:
źródło
Oto moje ulubione:
TikaEncodingDetector
Zależność:
Próba:
GuessEncoding
Zależność:
Próba:
źródło
CharsetDectector
.Z pewnością można sprawdzić poprawność pliku pod kątem określonego zestawu znaków, dekodując go za pomocą a
CharsetDecoder
i zwracając uwagę na błędy „zniekształcone dane wejściowe” lub „niezamapowalne znaki”. Oczywiście to mówi ci tylko wtedy, gdy zestaw znaków jest zły; nie mówi ci, czy jest poprawna. Do tego potrzebna jest podstawa porównawcza do oceny dekodowanych wyników, np. Czy wiesz wcześniej, czy znaki są ograniczone do jakiegoś podzbioru, czy też tekst jest zgodny z jakimś ścisłym formatem? Najważniejsze jest to, że wykrywanie zestawu znaków to zgadywanie bez żadnych gwarancji.źródło
Z jakiej biblioteki skorzystać?
W chwili pisania tego artykułu powstały trzy biblioteki:
Nie dołączam Apache Any23, ponieważ pod maską używa ICU4j 3.4.
Jak sprawdzić, który z nich wykrył właściwy zestaw znaków (lub możliwie najbliższy)?
Nie można poświadczyć zestawu znaków wykrytego przez każdą z powyższych bibliotek. Można jednak zapytać ich po kolei i ocenić otrzymaną odpowiedź.
Jak ocenić zwróconą odpowiedź?
Każdej odpowiedzi można przypisać jeden punkt. Im więcej punktów ma odpowiedź, tym większe zaufanie ma wykryty zestaw znaków. To jest prosta metoda punktacji. Możesz rozwinąć innych.
Czy jest jakiś przykładowy kod?
Oto pełny fragment implementujący strategię opisaną w poprzednich wierszach.
Ulepszenia:
guessEncoding
metoda odczytuje InputStream całkowicie. W przypadku dużych strumieni wejściowych może to stanowić problem. Wszystkie te biblioteki czytałyby cały strumień wejściowy. Oznaczałoby to duże zużycie czasu na wykrycie zestawu znaków.Możliwe jest ograniczenie początkowego ładowania danych do kilku bajtów i wykrywanie zestawu znaków tylko na tych kilku bajtach.
źródło
Powyższe biblioteki to proste detektory BOM, które oczywiście działają tylko wtedy, gdy na początku pliku znajduje się BOM. Spójrz na http://jchardet.sourceforge.net/, który skanuje tekst
źródło
O ile wiem, w tym kontekście nie ma ogólnej biblioteki, która byłaby odpowiednia dla wszystkich typów problemów. Dlatego dla każdego problemu należy przetestować istniejące biblioteki i wybrać najlepszą, która spełnia ograniczenia problemu, ale często żadna z nich nie jest odpowiednia. W takich przypadkach możesz napisać własny wykrywacz kodowania! Jak napisałem ...
Napisałem narzędzie meta java do wykrywania kodowania kodowania znaków na stronach HTML, używając IBM ICU4j i Mozilla JCharDet jako wbudowanych komponentów. Tutaj możesz znaleźć moje narzędzie, przeczytaj najpierw sekcję README. W moim artykule oraz w jego bibliografii można również znaleźć kilka podstawowych koncepcji tego problemu .
Poniżej zamieściłem kilka pomocnych komentarzy, których doświadczyłem w swojej pracy:
źródło
Znalazłem fajną bibliotekę innej firmy, która może wykryć rzeczywiste kodowanie: http://glaforge.free.fr/wiki/index.php?wiki=GuessEncoding
Nie testowałem tego szczegółowo, ale wydaje się, że działa.
źródło
Jeśli używasz ICU4J ( http://icu-project.org/apiref/icu4j/ )
Oto mój kod:
Pamiętaj, aby umieścić wszystkie try-catch potrzebne.
Mam nadzieję, że to działa dla Ciebie.
źródło
Jeśli nie znasz kodowania swoich danych, nie jest to łatwe do ustalenia, ale możesz spróbować zgadnąć je za pomocą biblioteki . Jest też podobne pytanie .
źródło
W przypadku plików ISO8859_1 nie ma łatwego sposobu na odróżnienie ich od ASCII. Jednak w przypadku plików Unicode można to zwykle wykryć na podstawie kilku pierwszych bajtów pliku.
Pliki UTF-8 i UTF-16 zawierają znacznik kolejności bajtów (BOM) na samym początku pliku. Zestawienie komponentów to nierozdzielająca przestrzeń o zerowej szerokości.
Niestety z powodów historycznych Java nie wykrywa tego automatycznie. Programy takie jak Notatnik sprawdzą BOM i zastosują odpowiednie kodowanie. Używając unix lub Cygwin, możesz sprawdzić BOM za pomocą polecenia plik. Na przykład:
W przypadku języka Java sugeruję sprawdzenie tego kodu, który wykryje popularne formaty plików i wybierze prawidłowe kodowanie: Jak odczytać plik i automatycznie określić prawidłowe kodowanie
źródło
Alternatywą dla TikaEncodingDetector jest użycie Tika AutoDetectReader .
źródło
W zwykłej Javie:
To podejście będzie próbować kodowania jeden po drugim, aż jedno zadziała lub zabraknie ich. (Przy okazji moja lista kodowań zawiera tylko te elementy, ponieważ są to implementacje zestawów znaków wymagane na każdej platformie Java, https://docs.oracle.com/javase/9/docs/api/java/nio/charset/Charset.html )
źródło
Czy potrafisz wybrać odpowiedni zestaw znaków w konstruktorze :
źródło