2015-10-16 4 views
3

J'ai besoin de convertir les caractères Doublebyte. Dans mon cas particulier Shift-Jis dans quelque chose de mieux à gérer, de préférence avec C++ standard.Conversion C++ ShiftJIS en UTF8

la question suivante a fini sans solution de contournement: Doublebyte encodings on MSVC (std::codecvt): Lead bytes not recognized

est donc ce qu'il ya quelqu'un avec une suggestion ou une référence sur la façon de gérer cette conversion avec la norme C++?

+0

"Mieux vaut gérer" pour quoi exactement? Une seule direction? (ShitJIS => somethingelse, mais pas somethingelse => ShiftJIS) – deviantfan

+0

Sry, pour l'affichage en UTF-8 par exemple. Dans une seule direction. Ce serait bien de savoir. – bob

Répondre

1

Normalement, je recommanderais ICU, mais pour cela seul, l'utiliser est beaucoup trop frais généraux. En dessous du code, il y a un lien vers un fichier contenant une table de conversion. Chargez dans votre programme, par exemple dans un tableau/vecteur de uint8_t nommé convTable (exactement 25088 octets), vous pouvez utiliser la fonction suivante pour convertir une chaîne ShiftJIS en UTF8 (à la fois comme std::string):

std::string sj2utf8(const std::string &input) 
{ 
    std::string output(3 * input.length(), ' '); 
    size_t indexin = 0, indexout = 0; 
    while(indexin < input.length()) 
    { 
     char group = ((uint8_t)input[indexin]) >> 4; 
     size_t offset = 0; 
     if(group == 0x8) offset = 0x100; 
     else if(group == 0x9) offset = 0x1100; 
     else if(group == 0xE) offset = 0x2100; 
     else group = 0; 
     if(group) 
     { 
      offset += (((uint8_t)input[indexin]) & 0xf) << 8; 
     } 
     else offset = input[indexin]; 
     indexin++; 
     if(group && indexin < input.length()) 
     { 
      offset |= (uint8_t)input[indexin++]; 
     } 
     offset <<= 1; 


     uint16_t value = (convTable[offset] << 8) | convTable[offset + 1]; 
     if(value < 0x80) 
     { 
      output[indexout++] = value; 
     } 
     else if(value < 0x800) 
     { 
      output[indexout++] = 0xC0 | (value >> 6); 
      output[indexout++] = 0x80 | (value & 0x3f); 
     } 
     else 
     { 
      output[indexout++] = 0xE0 | (value >> 12); 
      output[indexout++] = 0x80 | ((value & 0xfff) >> 6); 
      output[indexout++] = 0x80 | (value & 0x3f); 
     } 
    } 
    output.resize(indexout); 
    return output; 
} 

La fonction ne vérifie pas si l'entrée est données ShiftJIS valides, les caractères non valides généreront des espaces dans la sortie UTF8 (non seulement en raison de la ' ' dans le code, le fichier de données est que trop)

le fichier:
Téléchargement: http://www.filedropper.com/shiftjis
Généré à partir de: ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT

Contenu:
deux octets big endian valeurs unicode brutes (plus de deux octets pas nécessaire ici)
First 256 caractères (512 octets) pour les caractères de ShiftJIS d'un seul octet, la valeur 0x20 pour les invalides.
Puis 3 * 256 * 16 caractères pour les groupes 0x8 ???, 0x9 ??? et 0xE ???
= 25088 octet

+0

Merci Monsieur pour partager votre code! Je n'ai pas encore réussi à le faire fonctionner. Je suis passé dans une chaîne std :: qui devrait être un texte japonais décent et la sortie est toujours 0. Des suggestions? – bob

+0

@Sascha Avait une erreur, mais il aurait dû affecter uniquement le texte ASCII, pas les symboles japonais. Mis à jour le code dans la réponse, il devrait fonctionner tel quel. Êtes-vous sûr de charger correctement la matrice? D'où vient l'entrée, comment vérifiez-vous/imprimez-vous la sortie? – deviantfan

+0

J'ai lu le fichier entier avec ifstream donc j'ai un vecteur avec 25088 valeurs ressemblant à ce que j'ai vu dans l'éditeur binaire. Je passe simplement une chaîne avec des valeurs comme "\ x83 \ x41" ou sth similaire et la sortie sj2utf8 renvoie toujours 0. – bob