Perl: utf8 karakterek kihagyása latin1 fájlból

Van egy log fájlom, amit perlben fel kellene olvasnom. A logot készítő program nagyon ügyel rá, hogy csak latin1 karakterek kerüljenek a logba, ezért mindent elkódol ... majdnem mindent.
Néha azonban bekerül egy-egy utf-8 karakter is a logba, amit innentől nem tudok megfelelően kezelni.
Ezek az utf-8 karakterek mindig valamilyen hibából fakadnak, így elég lenne, ha ezeket le tudnám nyelni, vagy át tudnám ugrani. Az ilyen adatok csonkolása, sérülése nem lenne gond.
Célom, hogy csak latin1 karaktereket olvassak ki a fájlból.
Hiába nyitom meg azonban "< :encoding(Latin1)" módban a fájlt, továbbra is utf-8 karakterként kerül beolvasásra a sérült adat.
Van valakinek valamilyen ötlete?

Hozzászólások

Először megpróbálnám elhárítani az illegális utf-8 forrást.
A logot készítő program nagyon ügyel rá, hogy csak latin1 karakterek kerüljenek a logba, ezért mindent elkódol ...
Vajon regény is van a logban? ;)

A legkönnyebb út, ha az utf-8 egyértelmű, egy C konverter. A másik pedig az iconv, amivel egyértelműve kell alakítani a karaktereket. Mindkét szűrőt a beolvasás elé lehet kötni.

A program egy exim, és fél év óta először írt a logba olyan nem latin1 karaktereket, amiket fel kellene dolgoznom. Mivel ezek egy e-mail cím elején találhatóak, gyanítom, hogy eleve egy hibásan kódolt címmel akartak levelet küldeni. Az exim meg úgy tűnik, erre nem készült fel, így ezt nem kódolta el.
Lehet, hogy az utf-8 nem egyértelmű. Lehet, hogy csak valamilyen téves bináris adat, amit semmiképp nem lehet latin1-nek értelmezni.
iconv-val prbóbáltam konvertálni a teljes logfájlt, de megszakadt a konverzió karakterkódolási probléma miatt. Úgy látszik, a logban más helyeken is megjelennek bináris adatok, csak épp olyan részeken, amiket nekem nem kell feldolgoznom.
Emiatt maradnék annál, hogy a logfájlt nem bántom, és csak a beolvasott sort kezelném valamilyen konverzióval, hogy kidobáljam belőle a fránya karaktereket, vagy eleve már csak latin1-nek olvasnám be.

Lehet, hogy az utf-8 nem egyértelmű. Lehet, hogy csak valamilyen téves bináris adat, amit semmiképp nem lehet latin1-nek értelmezni.

Nem értem. A latin1 egy 8-bites karakterkódolás, ahol a 0..255 tartományban van 256 db karakter, mindegyikhez egy egybájtos kód tartozik. Hogy lehet bármi egy fájlban, amit nem lehet latin1-nek értelmezni???

Ez teljesen más helyzet!
A mail headerben (címben) a kódolások és a hibák száma együttvéve meghaladja a végtelent. ;) Érdekes módon szinte minden levelezőprogramban többé-kevésbé képesek voltak megoldani az elégséges megfejtést.

A karakterenkénti feldolgozás egyáltalán nem lassú. (Mint alant írod. Persze nem js-ben kell írni. ;))
Ha
- eldobható az illegális karaktertől a sor, akkor az első ilyet és a sorvéget kell csak megkeresni.
- egyéb hibára gyanakszol, akkor is működhet az algoritmus. (Kérdés, mi rondít oda?)
- ha többféle érvényes kódolás csúszik be, akkor
-- ki kell emelni a címet és
-- a megfejtéshez mail header parsert kell bevetni.

Jó buli!

Ritkán használom, de emlékeim szerint az iconv azt várja, hogy ha egy input fájlt utf-8-ról bármi másra akarsz kódolni, akkor a teljes input utf-8 kódolású, nem csak néhány karaktere. Viszont ha csak néhány karakter utf-8-as, akkor lehet benne bármennyi, utf-8-ban érvénytelen karakter. Így aztán nem csoda, hogy kódolási hibával leáll.

Erre egyébként van egy modul "It's better than nothing!" alapon: elég ügyes.


use Text::Unidecode qw(unidecode);
$bigyo="Шрек";
$ize=unidecode ($bigyo);
$ize=~ tr/\"\^\~\#\/\,\\\_//d; #gyakorlati tapasztalatból
print "\n$ize\n";

Kiirja, hogy Shrek.

Szerk.: Egyébként jobban érzékelteti a modul a működést ezzel a példával: "çŤрẮχŐőíé" -> "cTpAKhOoie"