2010-08-14 5 views
1

J'ai ce code simple:C++: std :: problème de chaîne

#include <iostream> 
#include <fstream> 

using namespace std; 

int main(void) 
{ 
    ifstream in("file.txt"); 
    string line; 
    while (getline(in, line)) 
    { 
     cout << line << " starts with char: " << line.at(0) << " " << (int) line.at(0) << endl; 
    } 
    in.close(); 
    return 0; 
} 

qui imprime:

0.000000 0.000000 0.010909 0.200000 starts with char: 32 
A 0.023636 0.000000 0.014545 0.200000 starts with char: A 65 
B 0.050909 0.000000 0.014545 0.200000 starts with char: B 66 
C 0.078182 0.000000 0.014545 0.200000 starts with char: C 67 

... 

, 0.152727 0.400000 0.003636 0.200000 starts with char: , 44 
< 0.169091 0.400000 0.005455 0.200000 starts with char: < 60 
. 0.187273 0.400000 0.003636 0.200000 starts with char: . 46 
> 0.203636 0.400000 0.005455 0.200000 starts with char: > 62 
/0.221818 0.400000 0.010909 0.200000 starts with char:/47 
? 0.245455 0.400000 0.009091 0.200000 starts with char: ? 63 
¡ 0.267273 0.400000 0.005455 0.200000 starts with char: � -62 
£ 0.285455 0.400000 0.012727 0.200000 starts with char: � -62 
¥ 0.310909 0.400000 0.012727 0.200000 starts with char: � -62 
§ 0.336364 0.400000 0.009091 0.200000 starts with char: � -62 
© 0.358182 0.400000 0.016364 0.200000 starts with char: � -62 
® 0.387273 0.400000 0.018182 0.200000 starts with char: � -62 
¿ 0.418182 0.400000 0.009091 0.200000 starts with char: � -62 
À 0.440000 0.400000 0.012727 0.200000 starts with char: � -61 
Á 0.465455 0.400000 0.014545 0.200000 starts with char: � -61 

étrange ... Comment puis-je obtenir vraiment le premier caractère du string?

Merci d'avance!

+0

@Martjn: Lorsque vous êtes * tagging * vos questions avec C++ il est nécessaire de mettre des balises pseudo tels que « C++: » dans le Titre. – dmckee

Répondre

8

Vous obtenez le premier caractère de la chaîne.

Mais il semble que la chaîne est une chaîne UTF-8 (ou éventuellement un autre format de caractères multi-octets).

Cela signifie que chaque symbole (glyphe) imprimé est composé de 1 (ou plusieurs caractères).
S'il s'agit de UTF-8, tout caractère hors de la plage ASCII (0-127) est composé de 2 caractères (ou plus) et le code d'impression de chaîne interprète correctement cela. Mais il n'est pas possible que le code d'impression de caractères décode correctement un seul caractère supérieur à 127.

Personnellement, je pense que les formats de caractères de largeur dynamique ne sont pas une bonne idée à utiliser en interne dans un programme (ils sont OK pour le transport et le stockage) car ils rendent la manipulation des chaînes beaucoup plus complexe. Je recommanderais que vous convertissiez la chaîne dans un format de largeur fixe pour le traitement interne puis le convertissiez en UTF-8 pour le stockage. Personnellement j'utiliserais UTF-16 (ou UTF-32 en fonction de ce que wchar_t est) en interne (oui je sais techniquement que UTF-16 n'est pas une largeur fixe mais dans toutes les circonstances d'enseignement raisonnables c'est une largeur fixe (quand on inclut sable-script alors nous pouvons avoir besoin d'utiliser UTF-32)). Vous avez juste besoin d'imprégner le flux d'entrée/sortie avec la facette codecvt appropriée pour la traduction automatique. En interne, le code peut ensuite être manipulé en tant que caractères simples en utilisant le type wchar_t.

+0

cela pourrait aussi aider http://stackoverflow.com/questions/402283/stdwstring-vs-stdstring – celavek

+0

Pourriez-vous s'il vous plaît poster un exemple qui utilise une facette 'codecvt' pour convertir de UTF-8 en' wchar_t'? – Philipp

+0

Trouvé le truc boost. Bien qu'il ressemble à du code bêta: http://beta.boost.org/doc/libs/1_35_0/libs/serialization/doc/codecvt.html –

0

Je pense que les derniers personnages appartiennent à la table ASCII étendu, ce qui C++ ne supporte pas

ASCII Table

Edit1: Non d'un rapide coup d'oeil les caractères sur le fond ne semble pas être prolongée ASCII aussi. peut-être vérifier ce que Martin York a dit.

0

chaîne est un conteneur pour char, qui est seulement un octet. Il ne doit être utilisé que pour les chaînes Ascii ou les données binaires. Tout ce qui n'est pas dans ce cas devrait utiliser Unicode, en utilisant wstring, un conteneur pour wchar_t.

Mais le problème de codage de votre texte Unicode existe toujours, pour cela, voir les réponses ci-dessus.

+0

'std :: string' peut stocker des chaînes Unicode si vous utilisez un encodage approprié tel que UTF-8. Unicode n'est pas un encodage. – Philipp

+0

Bien que cela soit possible, ce n'est pas très bon, car vous ne pouvez pas utiliser [0] de manière fiable. Quel est le point de construire des abstractions (caractères plutôt que octets) si vous les utilisez de manière incorrecte? – user420483

1

Le fichier est codé en UTF-8. Utilisez une bibliothèque Unicode tels que ICU pour obtenir l'accès aux points de code:

#include <iostream> 
#include <fstream> 
#include <utility> 

#include "unicode/utf.h" 

using namespace std; 

const pair<UChar32, int32_t> 
getFirstUTF8CodePoint(const string& str) { 
    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(str.data()); 
    const int32_t length = str.length(); 
    int32_t offset = 0; 
    UChar32 cp = 0; 
    U8_NEXT(ptr, offset, length, cp); 
    return make_pair(cp, offset); 
} 

int main(void) 
{ 
    ifstream in("file.txt"); 
    string line; 
    while (getline(in, line)) 
    { 
     pair<UChar32, string::size_type> cp = getFirstUTF8CodePoint(line); 
     cout << line << " starts with char: " << line.substr(0, cp.second) << " " << static_cast<unsigned long>(cp.first) << endl; 
    } 
    in.close(); 
    return 0; 
} 
Questions connexes