2010-07-08 7 views
11

Je demande à un extrait de code qui cin un texte unicode, concatène un autre unicode au premier texte unicode et le cout le résultat.Comment puis-je cin et cout du texte unicode?

P.S. Ce code m'aidera à résoudre un autre problème plus important avec Unicode. Mais avant que l'essentiel soit d'accomplir ce que je demande.

AJOUTÉ: BTW Je ne peux pas écrire dans la ligne de commande un symbole Unicode lorsque j'exécute le fichier exécutable. Comment je devrais faire ça?

+2

Unicode n'est pas assez précis. Utilisez-vous UTF- [8/16/32]? Voulez-vous utiliser la même représentation en interne et quand elle est sérialisée dans un fichier? Si vous voulez convertir des représentations voulez-vous le faire manuellement ou via les paramètres régionaux en utilisant la facette codecvt? –

+0

Comme vous le souhaitez !!! Pas de fichier et rien d'autre cin, et cout ça tout! – Narek

+0

Après avoir lu divers threads sur ce sujet, ma conclusion est qu'il est impossible de faire en C++. Supprimez 'cin',' cout' et tout le reste des normes C++ et C et utilisez les fonctions Windows simples 'ReadConsoleW' et' WriteConsoleW'. Les standards C et C++ sont juste cassés à cet égard. – Philipp

Répondre

5

Voici un exemple qui montre quatre méthodes différentes, dont seule la troisième (C conio) et le quatrième (API Windows native) travail (mais seulement si stdin/stdout ne sont pas redirigés) . Notez que vous avez toujours besoin d'une police qui contient le caractère que vous voulez montrer (Lucida Console supporte au moins le grec et le cyrillique). Notez que tout ici est complètement non portable, il n'y a tout simplement aucun moyen portable d'entrer/sortir des chaînes Unicode sur le terminal.

#ifndef UNICODE 
#define UNICODE 
#endif 

#ifndef _UNICODE 
#define _UNICODE 
#endif 

#define STRICT 
#define NOMINMAX 
#define WIN32_LEAN_AND_MEAN 

#include <iostream> 
#include <string> 
#include <cstdlib> 
#include <cstdio> 

#include <conio.h> 
#include <windows.h> 

void testIostream(); 
void testStdio(); 
void testConio(); 
void testWindows(); 

int wmain() { 
    testIostream(); 
    testStdio(); 
    testConio(); 
    testWindows(); 
    std::system("pause"); 
} 

void testIostream() { 
    std::wstring first, second; 
    std::getline(std::wcin, first); 
    if (!std::wcin.good()) return; 
    std::getline(std::wcin, second); 
    if (!std::wcin.good()) return; 
    std::wcout << first << second << std::endl; 
} 

void testStdio() { 
    wchar_t buffer[0x1000]; 
    if (!_getws_s(buffer)) return; 
    const std::wstring first = buffer; 
    if (!_getws_s(buffer)) return; 
    const std::wstring second = buffer; 
    const std::wstring result = first + second; 
    _putws(result.c_str()); 
} 

void testConio() { 
    wchar_t buffer[0x1000]; 
    std::size_t numRead = 0; 
    if (_cgetws_s(buffer, &numRead)) return; 
    const std::wstring first(buffer, numRead); 
    if (_cgetws_s(buffer, &numRead)) return; 
    const std::wstring second(buffer, numRead); 
    const std::wstring result = first + second + L'\n'; 
    _cputws(result.c_str()); 
} 

void testWindows() { 
    const HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE); 
    WCHAR buffer[0x1000]; 
    DWORD numRead = 0; 
    if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return; 
    const std::wstring first(buffer, numRead - 2); 
    if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return; 
    const std::wstring second(buffer, numRead); 
    const std::wstring result = first + second; 
    const HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    DWORD numWritten = 0; 
    WriteConsoleW(stdOut, result.c_str(), result.size(), &numWritten, NULL); 
} 
  • Edit 1: J'ai ajouté une méthode basée sur conio.
  • Edit 2: J'ai foiré autour avec _O_U16TEXT un peu comme décrit dans le blog de Michael Kaplan, mais apparemment seulement eu wgets interpréter les données (8 bits) de ReadFile en UTF-16. Je vais enquêter un peu plus loin pendant le week-end.
+0

Merci de me dire aussi comment écrire en ligne de commande en Unicode? Je ne peux pas! Il ignore et écrit en latin – Narek

+0

Aussi, vous pouvez écrire "main" au lieu de "wmain", non ? – Narek

+0

Si vous voulez lire les arguments de la ligne de commande, déclarez 'wmain' comme' int wmain (int argc, wchar_t ** argv) '(le' w' n'est pas une faute de frappe!) – Philipp

-1

Cela dépend du système d'exploitation. Si votre OS comprend, vous pouvez simplement lui envoyer des séquences UTF-8. Selon le type d'Unicode que vous entendez,

+0

Il est sur Windows, qui utilise UTF-16, mais nécessite des fonctions API spéciales ('ReadConsole' /' WriteConsole') pour travailler avec du texte Unicode. – Philipp

8

Je suppose que vous voulez dire que vous travaillez avec std::wstring cependant. Dans ce cas, utilisez std::wcin et std::wcout.

Pour la conversion entre encodages vous pouvez utiliser les fonctions de votre OS comme pour Win32: WideCharToMultiByte, MultiByteToWideChar ou vous pouvez utiliser une bibliothèque comme libiconv

+1

A ce stade, vous pouvez utiliser UTF-16 au lieu de UTF-8 si votre système d'exploitation le comprend. –

+0

+1: wcout pour wstring pour wchar_t (principalement UTF-16 de fenêtre), cout pour string pour char (Linux, UTF-8 par défaut) – rubenvb

+1

'wcin' et' wcout' ne fonctionnent pas sous Windows. – Philipp

0

Si vous avez un texte réel (par exemple une chaîne de caractères logiques), puis insérez aux larges cours d'eau à la place. Les flux larges encoderont automatiquement vos caractères pour qu'ils correspondent aux bits attendus par le codage des paramètres régionaux. (Et si vous avez des bits codés à la place, les flux vont décoder les bits, puis les réencoder pour les faire correspondre aux paramètres régionaux.)

Il existe une solution moindre si vous SAVEZ que vous avez des bits codés en UTF (c'est-à-dire un tableau des bits destinés à être décodés en une chaîne de caractères logiques) ET vous CONNAISSEZ que la cible du flux de sortie attend ce même format de bits, alors vous pouvez ignorer les étapes de décodage et de recodage et écrire() les bits comme si. Cela fonctionne uniquement lorsque vous savez que les deux côtés utilisent le même format de codage, ce qui peut être le cas pour les petits utilitaires qui ne sont pas destinés à communiquer avec des processus dans d'autres paramètres régionaux.

+2

Il n'y a pas d'encodage local sous Windows et donc les flux larges ne fonctionnent pas. – Philipp

6

J'ai eu un problème similaire dans le passé, dans mon cas imbue et sync_with_stdio fait l'affaire. Essayez ceci:

#include <iostream> 
#include <locale> 
#include <string> 

using namespace std; 

int main() { 
    ios_base::sync_with_stdio(false); 
    wcin.imbue(locale("en_US.UTF-8")); 
    wcout.imbue(locale("en_US.UTF-8")); 

    wstring s; 
    wstring t(L" la Polynésie française"); 

    wcin >> s; 
    wcout << s << t << endl; 
    return 0; 
} 
+1

Avez-vous testé ce code? Je reçois une erreur d'exécution! – Narek

+2

J'ai débogué, les coutures cette ligne est le problème: wcin.imbue (locale ("en_US.UTF-8")); – Narek

+1

@Narek Oui, j'ai testé le code. Il fonctionne sans problèmes sur mon Ubuntu. Quel système avez-vous? – Bolo