Comment utiliser l'Unicode en C++?

en Supposant un programme très simple:

  • demander un nom.
  • stocker le nom dans une variable.
  • afficher le contenu variable à l'écran.

c'est si simple que c'est la première chose qu'on apprend.

mais mon problème est que je ne sais pas comment faire la même chose si j'entre le nom en utilisant des caractères japonais.

Donc, si vous savez comment le faire en C++, veuillez me montrer un exemple (que je peux compiler et test)

Merci.


user362981 : Merci pour votre aide. J'ai compilé le code que vous avez écrit sans problème, la fenêtre de la console apparaît et je ne peux pas entrer de caractères japonais (en utilisant IME). Aussi, si Je change un mot de votre code ("hello") pour un qui contient des caractères japonais, il ne sera pas non plus afficher ces.

Svisstack: merci aussi pour votre aide. Mais quand je compile ton code j'ai le erreur:

warning: deprecated conversion from string constant to 'wchar_t*'
error: too few arguments to function 'int swprintf(wchar_t*, const wchar_t*, ...)'
error: at this point in file
warning: deprecated conversion from string constant to 'wchar_t*'
26
demandé sur Josh Kelley 2010-06-10 03:40:33

5 réponses

Vous allez obtenir beaucoup de réponses sur les caractères larges. Caractères larges, spécifiquement wchar_t ne sont pas égales Unicode. Vous pouvez les utiliser (avec quelques pièges) pour stocker Unicode, tout comme vous pouvez un unsigned char. wchar_t est extrêmement dépendant du système. Pour citer l' Standard Unicode, version 5.2 du chapitre 5:

et

La largeur de wchar_t le compilateur, et peut être aussi petit que 8 bits. Conséquent, les programmes qui doivent être portables à travers n'importe quel compilateur C ou C++ ne devraient pas utiliser wchar_t pour stocker du texte Unicode. Le wchar_t le type est destiné au stockage de wide défini par le compilateur caractères, qui peuvent être des caractères Unicode dans certains compilateurs.

donc, c'est une implémentation définie. Voici deux implémentations: sur Linux,wchar_t est de 4 octets de large, et représente du texte dans L'encodage UTF-32 (indépendamment de la locale actuelle). (Soit BE ou LE selon votre système, selon ce qui est natif.) Windows, cependant, a une largeur de 2 octets wchar_t, et représente les unités de code UTF-16 avec eux. Complètement différent.

un meilleur chemin: renseignez-vous sur les lieux, comme vous aurez besoin de le savoir. Par exemple, parce que j'ai ma configuration de l'environnement pour utiliser l'UTF-8 (Unicode), le programme suivant utilise Unicode:

#include <iostream>

int main()
{
    setlocale(LC_ALL, "");
    std::cout << "What's your name? ";
    std::string name;
    std::getline(std::cin, name);
    std::cout << "Hello there, " << name << "." << std::endl;
    return 0;
}

...

$ ./uni_test
What's your name? 佐藤 幹夫
Hello there, 佐藤 幹夫.
$ echo $LANG
en_US.UTF-8

mais il n'y a rien D'Unicode à ce sujet. Il se lit simplement en caractères, qui viennent comme UTF-8 parce que j'ai mon environnement de cette façon. Je pourrais aussi bien dire " je suis en partie tchèque, utilisez ISO-8859-2": tout à coup, le programme est saisi dans ISO-8859-2, mais comme il est juste de régurgiter, il n'a pas d'importance, le programme fonctionnera toujours correctement.

maintenant, si cet exemple avait lu dans mon nom, et ensuite essayé de l'écrire dans un fichier XML, et stupidement écrit <?xml version="1.0" encoding="UTF-8" ?> au sommet, ce serait bien quand mon terminal était en UTF-8, mais mal quand mon terminal était en ISO-8859-2. Dans ce dernier cas, il faudrait le convertir avant de le sérialiser en XML. fichier. (Ou, il suffit D'écrire ISO-8859-2 comme encodage pour le fichier XML.)

sur de nombreux systèmes POSIX, la locale actuelle est typiquement UTF-8, car elle offre plusieurs avantages à l'utilisateur, mais ce n'est pas garanti. Outputting UTF-8 to stdout est généralement correcte, mais pas toujours. Disons que J'utilise ISO-8859 - 2: Si vous produisez sans réfléchir une ISO-8859-1" è" (0xE8) à mon terminal, je verrai un" č" (0xE8). De même, si vous produisez un UTF-8 "è" (0xC3 0xA8), je vais voir (ISO-8859-2)" ¿" (0xC3 0xA8). Ce vomissement de caractères incorrects a été appelé Mojibake.

souvent, vous mélangez des données, et ça n'a pas beaucoup d'importance. Cela entre généralement en jeu lorsque vous avez besoin de sérialiser les données. (De nombreux protocoles internet utilisent UTF-8 ou UTF-16, par exemple: si vous avez des données d'un terminal ISO-8859-2, ou un fichier texte encodé dans Windows-1252, alors vous devez le convertir, ou vous allez envoyer Mojibake.)

malheureusement, il s'agit de l'État du support Unicode, en C et C++. Vous devez vous rappeler: ces langues sont vraiment agnostiques-système, et ne se lient à aucune façon particulière de le faire. Que comprend le caractère fixe. Il ya des tonnes de bibliothèques, cependant, pour traiter avec Unicode et d'autres jeux de caractères.

en fin de Compte, ce n'est pas si compliqué que ça: savoir dans quel encodage se trouvent vos données, et savoir dans quel encodage votre la sortie devrait être arrivée. S'ils ne sont pas les mêmes, vous devez faire une conversion. Ceci s'applique que vous utilisiez std::cout ou std::wcout. Dans mes exemples, stdin ou std::cin et stdout/std::cout étaient parfois en UTF-8, parfois ISO-8859-2.

36
répondu Thanatos 2010-06-11 04:13:17

essayez de remplacer cout par wcout, cin par wcin, et string par wstring. En fonction de votre plateforme, cela peut fonctionner:

#include <iostream>
#include <string>

int main() {
  std::wstring name;
  std::wcout << L"Enter your name: "; 
  std::wcin >> name;
  std::wcout << L"Hello, " << name << std::endl;
}

Il y a d'autres façons, mais c'est en quelque sorte la réponse "changement minimal".

1
répondu EvanED 2010-06-09 23:46:48

vous pouvez faire des choses simples avec le support de caractères génériques dans votre OS de choix, mais généralement C++ n'a pas de bon support intégré pour unicode, donc vous serez mieux à long terme en regardant dans quelque chose comme ICU.

1
répondu Nick Bastin 2010-06-10 00:48:03
#include <stdio.h>
#include <wchar.h>

int main()
{
    wchar_t name[256];

    wprintf(L"Type a name: ");
    wscanf(L"%s", name);

    wprintf(L"Typed name is: %s\n", name);

    return 0;
}
1
répondu Svisstack 2010-06-10 10:04:40

Pré-requis: http://www.joelonsoftware.com/articles/Unicode.html

L'article ci-dessus est à lire absolument, qui explique ce qu'unicode est mais quelques-uns qui traînent questions reste. Oui UNICODE a un point de code unique pour chaque caractère dans chaque langue et en outre ils peuvent être encodés et stockés dans la mémoire potentiellement différent de ce que le code réel est. De cette façon, nous pouvons sauver la mémoire par exemple en utilisant L'encodage UTF-8 qui est grand si la langue soutenu est juste anglais et donc la représentation de mémoire est essentiellement la même que ASCII – ce bien sûr connaître l'encodage lui-même. En théorie, si nous connaissons l'encodage, nous pouvons stocker ces caractères UNICODE plus longs comme nous le voulons et le relire. Mais le monde réel est un peu différent.

comment stocker un caractère/chaîne UNICODE dans un programme C++? Dont l'encodage utilisez-vous? La réponse est que vous n'utilisez aucun encodage mais vous stockez directement les points de code UNICODE dans un unicode chaîne de caractères tout comme vous stockez des caractères ASCII dans la chaîne ASCII. La question Est de savoir quelle taille de caractère utiliser puisque les caractères UNICODE n'ont pas de taille fixe. La réponse simple est que vous choisissez la taille de caractère qui est assez large pour contenir le point de code de caractère le plus élevé (langue) que vous voulez soutenir.

la théorie selon laquelle un caractère UNICODE peut prendre 2 octets ou plus est toujours vraie et cela peut créer une certaine confusion. Ne devrions-nous pas stocker des points de code en 3 ou 4 octets qu'est-ce qui représente vraiment tous les caractères unicode? Pourquoi Visual C++ stocke-t-il unicode dans wchar_t alors qui est seulement 2 octets, clairement pas assez pour stocker chaque point de code UNICODE?

la raison pour laquelle nous stockons le point de code de caractère UNICODE dans 2 octets dans Visual C++ est en fait exactement la même raison pour laquelle nous stockons le caractère ASCII (=anglais) dans un octet. À l'époque, nous pensions que l'anglais donc un octet a été assez. Maintenant, nous pensons à la plupart des langages disponibles mais pas tous donc nous utilisons 2 octets ce qui est suffisant. Oui il est vrai que cette représentation ne nous permettra pas de représenter les points de code qui prennent 3 octets ou plus mais nous ne nous soucions pas de ceux encore parce que ces gens n'ont même pas encore acheté un ordinateur. Oui nous n'utilisons pas 3 ou 4 octets parce que nous sommes encore avares de mémoire, pourquoi stocker le octet 0(zéro) supplémentaire avec chaque caractère alors que nous n'allons jamais l'utiliser (cette langue). Encore une fois c'est exactement les mêmes raisons ASCII stockait chaque caractère dans un octet, pourquoi stocker un caractère dans 2 octets ou plus quand l'anglais peut être représenté dans un octet et de la place pour ces caractères spéciaux supplémentaires!

en théorie 2 octets ne sont pas suffisants pour présenter chaque point de code Unicode, mais c'est suffisant pour contenir tout ce dont nous pouvons nous soucier pour l'instant. Une vraie représentation de chaîne de caractères UNICODE pourrait stocker chaque caractère en 4 octets, mais nous ne nous soucions pas de ces langues.

imaginez 1000 ans a partir de Maintenant quand nous trouvons des aliens amicaux et en abondance et que nous voulons communiquer avec eux en incorporant leurs innombrables langues. Une taille de caractère unicode simple va augmenter encore peut-être à 8 octets pour accommoder tous leurs points de code. Cela ne signifie pas que nous devrions commencer à utiliser 8 octets pour chaque caractère unicode maintenant. La mémoire est une ressource limitée, nous allouons ce dont nous avons besoin.

puis-je traiter la chaîne UNICODE comme une chaîne de Style C?

en C++ une chaîne ASCII peut encore être manipulé en C++ et c'est assez courant en l'attrapant par son pointeur char * où les fonctions C peuvent être appliquées. Cependant, appliquer les fonctions C style string actuelles sur une chaîne UNICODE n'aura aucun sens parce qu'elle pourrait avoir un seul octet nul qui termine une chaîne C.

une chaîne UNICODE n'est plus un tampon simple de texte, mais elle est maintenant plus compliquée qu'un flux de caractères octet simple se terminant par un octet nul. Ce tampon pourrait être manipulé par son pointeur même en C mais il exigera un UNICODE appels compatibles ou une bibliothèque C qui pourrait lire et écrire ces chaînes et effectuer des opérations.

ceci est rendu plus facile en C++ avec une classe spécialisée qui représente une chaîne UNICODE. Cette classe gère la complexité du tampon unicode string et fournit une interface facile. Cette classe décide également si chaque caractère de la chaîne unicode est de 2 octets ou plus – ce sont des détails d'implémentation. Aujourd'hui, il peut utiliser wchar_t (2 octets) mais demain il peut utiliser 4 octets pour chaque caractère pour supporter plus (moins connu) langue. C'est pourquoi il est toujours préférable d'utiliser TCHAR qu'une taille fixe qui correspond à la bonne taille lorsque l'implémentation change.

comment indexer une chaîne UNICODE?

il est également intéressant de noter, et particulièrement dans le style C de manipulation des chaînes, qu'ils utilisent l'index pour parcourir ou trouver des sous-chaînes dans une chaîne. Cet indice dans la chaîne ASCII correspondait directement à la position de l'élément dans cette chaîne, mais il n'a pas de sens dans une chaîne UNICODE et doit être évitée.

Qu'arrive-t-il à la chaîne qui se termine par un octet nul?

les chaînes UNICODE se terminent-elles toujours par un octet nul? Est-ce qu'un seul octet nul suffit pour terminer la chaîne? Il s'agit d'une question d'implémentation mais un octet nul est toujours un point de code unicode et comme tous les autres points de code, il doit toujours être de la même taille que n'importe quel autre(surtout lorsqu'il n'y a pas d'encodage). Ainsi, le caractère NULL doit être de deux octets si l'implémentation de la chaîne unicode est basée sur wchar_t. Tous les points de code UNICODE seront représentés par la même taille, qu'il s'agisse d'un octet nul ou d'un autre.

est-ce que Visual C++ Debugger affiche du texte UNICODE?

Oui, si le texte de la mémoire tampon est de type LPWSTR ou de tout autre type, qui prend en charge UNICODE, Visual Studio 2005 et jusqu'en charge l'affichage du texte international dans le débogueur fenêtre d'observation (à condition que les polices et les les dossiers de langue sont installés bien sûr).

Résumé:

C++ n'utilise aucun encodage pour stocker les caractères unicode mais stocke directement les points de code UNICODE pour chaque caractère dans une chaîne. Il doit choisir une taille de caractère assez grande pour contenir le plus grand caractère des langues souhaitables (parlant librement) et cette taille de caractère sera fixée et utilisée pour tous les caractères de la chaîne.

aujourd'hui, 2 octets sont suffisants pour représenter la plupart des langues que nous nous soucions, c'est pourquoi il est utilisé pour représenter le point de code. À l'avenir, si une nouvelle colonie spatiale conviviale était découverte qui veut communiquer avec eux, nous devrons assigner de nouveaux pionts unicode code à leur langue et utiliser une taille de caractère plus grande pour stocker ces chaînes.

0
répondu zar 2016-05-11 13:58:39