2009-08-28 7 views
0

J'ai un observateur de fichier qui saisit le contenu d'un fichier en croissance encodé avec utf-16LE. Le premier bit de données qui y est écrit a la BOM disponible - je l'utilisais pour identifier l'encodage par rapport à UTF-8 (dont la plupart des fichiers entrants sont encodés). J'attrape la nomenclature et ré-encoder en UTF-8 afin que mon analyseur ne panique pas. Le problème est que, comme il s'agit d'un fichier en pleine croissance, toutes les données ne contiennent pas la nomenclature.Comment puis-je identifier différents encodages sans utiliser de nomenclature?

Voici ma question - sans préfixer la nomenclature octets à chaque ensemble de données dont je dispose (parce que je ne dispose pas de contrôle sur la source) puis je peux chercher des octets nuls qui sont inhérents au format UTF-16 \ 000, puis l'utiliser comme identifiant au lieu de la nomenclature? Cela me causera-t-il des maux de tête sur la route?

Mon architecture implique une application Web ruby ​​enregistrant les données reçues dans un fichier temporaire lorsque mon analyseur écrit en java le récupère.

Écrire maintenant mon identification/code réencodage ressemble à ceci:

// guess encoding if utf-16 then 
    // convert to UTF-8 first 
    try { 
    FileInputStream fis = new FileInputStream(args[args.length-1]); 
    byte[] contents = new byte[fis.available()]; 
    fis.read(contents, 0, contents.length); 

    if ((contents[0] == (byte)0xFF) && (contents[1] == (byte)0xFE)) { 
     String asString = new String(contents, "UTF-16"); 
     byte[] newBytes = asString.getBytes("UTF8"); 
     FileOutputStream fos = new FileOutputStream(args[args.length-1]); 
     fos.write(newBytes); 
     fos.close(); 
    } 

    fis.close(); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 

MISE À JOUR

Je veux soutenir des choses comme euros, em-tirets et autres caractères en tant que tels. Je modifié le code ci-dessus pour ressembler à ceci et il semble passer tous mes tests pour ces personnages:

// guess encoding if utf-16 then 
    // convert to UTF-8 first 
    try { 
    FileInputStream fis = new FileInputStream(args[args.length-1]); 
    byte[] contents = new byte[fis.available()]; 
    fis.read(contents, 0, contents.length); 
    byte[] real = null; 

    int found = 0; 

    // if found a BOM then skip out of here... we just need to convert it 
    if ((contents[0] == (byte)0xFF) && (contents[1] == (byte)0xFE)) { 
     found = 3; 
     real = contents; 

    // no BOM detected but still could be UTF-16 
    } else { 

     for(int cnt=0; cnt<10; cnt++) { 
     if(contents[cnt] == (byte)0x00) { found++; }; 

     real = new byte[contents.length+2]; 
     real[0] = (byte)0xFF; 
     real[1] = (byte)0xFE; 

     // tack on BOM and copy over new array 
     for(int ib=2; ib < real.length; ib++) { 
      real[ib] = contents[ib-2]; 
     } 
     } 

    } 

    if(found >= 2) { 
     String asString = new String(real, "UTF-16"); 
     byte[] newBytes = asString.getBytes("UTF8"); 
     FileOutputStream fos = new FileOutputStream(args[args.length-1]); 
     fos.write(newBytes); 
     fos.close(); 
    } 

    fis.close(); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 

Que pensez-vous tous?

+0

Je ne comprends pas le problème (vous faites référence dans le premier paragraphe). Bien sûr, tous les fragments n'auront pas la BOM - mais sûrement le début du fichier. Donc, pour chaque fichier, rappelez-vous si vous avez vu la nomenclature, et si oui, traitez-la en UTF-16. –

+0

Vous n'avez sûrement pas d'encodage mixte dans un seul fichier? –

+0

Je n'ai pas le contrôle du fichier qui est en croissance - c'est pourquoi je ne peux pas simplement rembobiner le fichier. Je n'ai pas de codage mixte dans le même fichier - mais j'ai des codages mixtes qui traversent un réseau vers un analyseur qui accepte les codages mixtes. – eyberg

Répondre

6

En général, vous ne pouvez pas identifier le codage de caractères d'un flux de données avec une précision de 100%. Le mieux que vous puissiez faire est d'essayer de décoder en utilisant un ensemble limité de codages attendus, puis d'appliquer des heuristiques au résultat décodé pour voir s'il ressemble au texte dans la langue attendue. (Mais toute heuristique donnera des faux positifs et des faux négatifs pour certains flux de données.) Sinon, mettez un humain dans la boucle pour décider quel décodage est le plus logique.

Une meilleure solution consiste à redéfinir votre protocole de sorte que tout ce qui fournit les données doit également fournir le schéma de codage utilisé pour les données. (Et si vous ne pouvez pas, blâmer quiconque est responsable de la conception/mise en œuvre du système qui ne peut pas vous donner un schéma d'encodage!).

EDIT: à partir de vos commentaires sur la question, les fichiers de données sont livrés via HTTP. Dans ce cas, vous devez vous assurer que votre serveur HTTP saisit l'en-tête "content-type" des requêtes POST qui délivrent les données, extrayez le jeu de caractères/encodage de l'en-tête et enregistrez-le d'une manière traiter avec.

0

Cela vous causera des maux de tête sur la route, sans aucun doute à ce sujet. Vous pouvez vérifier l'alternance des octets zéro pour les cas simplistes (ASCII uniquement, UTF-16, ordre des octets) mais dès que vous commencez à obtenir un flux de caractères au-dessus du point de code 0x7f, cette méthode devient inutile.

Si vous avez la poignée de fichier, le mieux est de sauvegarder le pointeur de fichier en cours, de chercher au début, de lire la nomenclature et de revenir à la position d'origine.

Soit cela ou se souvenir de la nomenclature en quelque sorte. S'appuyant sur le contenu des données est mauvaise idée sauf si vous êtes absolument certain que la plage de caractères sera restreinte pour toutes les entrées.

+0

S'appuyer sur la nomenclature est une mauvaise idée, sauf si vous êtes absolument certain que le fichier en aura un. – dan04

+0

"Le premier bit de données qui y est écrit a la BOM disponible" était dans la question, donc j'étais absolument certain :-) – paxdiablo

0

This question contient quelques options de détection de caractères qui ne semblent pas nécessiter de nomenclature.

Mon projet utilise actuellement jCharDet, mais il se peut que je devrais examiner certaines des autres options répertoriées ici, car jCharDet n'est pas fiable à 100%.

+2

@jwaddell: Aucun schéma de détection de caractères ne sera fiable à 100%. –

Questions connexes