UTF-8-e vagy?

Egy érdekes probléma: hogyan döntsük el egy fájlról, hogy milyen karakterkódolással készült? Igazából algoritmus kellene rá, a Total Commander F3-as nézőkéje nem mindig jó megoldás. Főleg a bemenet gépi ellenőrzésekor nem.

Kis keresgélés után a Mozilla-féle karakterkódolás-detektáló algoritmus java verziójára akadtam. Kipróbáltam, de nem jött be. A latin2 és ASCII kódolást felismerte, az UTF-8-at és a latin1-et nem. Pedig az UTF-8 lenne a legérdekesebb. Igazából egy boolean isUtf8(byte[]) metódus is elegendő lehet a legtöbb feladatra.

Aztán találtam belőle egy fejlettebb változatot, ami már az UTF-8-cal is megbirkózik.

Egy másik jó választás a GuessEncoding. Ez ugyan csak az UTF-8 kódolást ismeri (meg néhány másikat a BOM-ból képes kitalálni), de cserébe viszonylag egyszerű, könnyen módosítható.

Kipróbáltam a Java API idevágó osztályait is, hátha jelzik a hibát, ha UTF-8 helyett valami mást találnak. Fájlok beolvasásával kapcsolatban három módszert nézegettem. Az első a FileReader volt, de a dokumentációja szerint az alapértelmezett karakterkódolással dolgozik, ha nem erre van szükségünk, akkor az InputStreamReader és a FileInputStream kombinációját kell alkalmaznunk. A harmadik jelölt pedig a Scanner osztály volt.

Mivel a FileReader-nek nincs olyan konstruktora, amelynek meg lehetne adni a karakterkódolást, így ezzel nem is foglalkoztam tovább. A rendszer alapértelmezett karakterkódolása biztos, hogy rendszerről-rendszerre változhat, úgyhogy erre nem érdemes építeni. Az InputStreamReader és Scanner osztályok rendelkeznek olyan konstruktorral, ami karakterkészletet vár. Ezeknek mindig UTF-8-at adtam meg.

A Scanner nem jelzi, ha hibát talál az UTF-8 fájlban. Egyszerűen csak onnantól kezdve nem ad vissza semmit. Az InputStreamReader visszaad valamit, de nem az igazi. A Scanner reakciója szimpatikusabb, legalább utalni fog valami a hibára, ami lehet, hogy egyébként észrevehetetlen lenne. Például ha egy nagyobb adatfájl belsejében fordul elő egy hibás kódolású karakter.

Az eddigiek miatt tanácsos lehet a tényleges adatfeldolgozás megkezdése előtt az egész fájl UTF-8 megfelelőségét ellenőrizni. Erre a GuessEncoding váza tökéletes, csupán néhány módosítás szükséges hozzá:

  • Ha nem sikerül detektálni a karakterkódolást, akkor ne a rendszer alapértelmezett karakterkódolását adja vissza, hanem dobjon mondjuk egy UnknownCharsetException-t.
  • Az egész fájlt be kell olvasnunk, nem elég csak a fájl első néhány kilobájtja alapján tippelni. (Ahogyan azt egyébként a Mozilla-féle algoritmus is teszi.)

A magyar ékezetes karakterekhez egyébként egy reguláris kifejezés is elegendő lehet. (Csak ne Scannerrel olvassuk be a fájlt, mert akkor csak az első hibás karakter előtti tartalmat kapjuk meg, amire valószínűleg illeszkedni fog a kifejezés.)

Hozzászólások

karakter dekódolás

Nem az InputStreamReader az ami nem dob hibát, hanem a CharsetDecoder ami alatta van. Ha az kell, hogy hibát dobjon, akkor nem a charset nevét kell megadni a konstruktorban hanem egy olyan CharsetDecoder-t, ami hibát dob.

CharsetDecoder-t a charset-ből kapsz newDecoder()-rel, és a többit

http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/CharsetDecoder.html

alapján. Tehát nem kell előre leellenőrizni, hogy tényleg UTF-8-e, lehet közben is hibát kapni.

Tartalom átvétel