2010-07-08 20 views
11

Pido un fragmento de código que cin un texto unicode, concatena otro unicode al primer texto Unicode y el resultado es cout.¿Cómo puedo cin y cout algún texto Unicode?

P.S. Este código me ayudará a resolver otro problema mayor con Unicode. Pero antes, la clave es lograr lo que pido.

AGREGADO: BTW No puedo escribir en la línea de comandos ningún símbolo Unicode cuando ejecuto el archivo ejecutable. ¿Cómo debería hacer eso?

+2

Unicode no es lo suficientemente exacto. ¿Estás usando UTF- [8/16/32]? ¿Desea usar la misma representación internamente y cuando se serializa en un archivo? Si desea convertir representaciones, ¿quiere hacerlo manualmente o mediante la configuración regional utilizando codecvt facet? –

+0

Como quieras !!! ¡Sin archivo y nada más cin, y cout eso! – Narek

+0

Después de leer varios hilos sobre este tema, mi conclusión es que es imposible hacerlo en C++. Suelte 'cin',' cout' y todo lo demás de los estándares C++ y C y use las funciones simples de Windows 'ReadConsoleW' y' WriteConsoleW'. Los estándares C y C++ simplemente se han roto a este respecto. – Philipp

Respuesta

5

Aquí es un ejemplo que muestra cuatro métodos diferentes, de los cuales sólo el tercero (C conio) y el cuarto (API nativa de Windows) trabajo (pero sólo si la entrada estándar/salida estándar no son redirigidos) . Tenga en cuenta que todavía necesita una fuente que contenga el carácter que desea mostrar (la consola Lucida admite al menos caracteres griegos y cirílicos). Tenga en cuenta que aquí todo es completamente no portátil, simplemente no hay una forma portátil de entrada/salida de cadenas Unicode en el 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); 
} 
  • Editar 1: He añadido un método basado en conio.
  • Editar 2: He ensuciado alrededor con _O_U16TEXT un poco como se describe en el blog de Michael Kaplan, pero que al parecer sólo tenía wgets interpretar los datos (8 bits) de ReadFile como UTF-16. Voy a investigar esto un poco más durante el fin de semana.
+0

Gracias. Díganme también cómo escribir en la línea de comando en Unicode? No puedo! Ignora y escribe en latín – Narek

+0

También es posible que desee escribir "main" en lugar de "wmain", no ? – Narek

+0

Si quieres leer los argumentos de la línea de comando, declara 'wmain' como' int wmain (int argc, wchar_t ** argv) '(la' w' no es un error!). – Philipp

-1

Depende del sistema operativo. Si su OS entiende, puede simplemente enviar secuencias UTF-8.

+0

Está en Windows, que usa UTF-16, pero requiere funciones API especiales ('ReadConsole' /' WriteConsole') para trabajar con texto Unicode. – Philipp

8

Según el tipo de Unicode que quieras decir. Supongo que quiere decir que solo está trabajando con std::wstring. En ese caso, use std::wcin y std::wcout.

para la conversión entre codificaciones que puede utilizar sus funciones del sistema operativo como para Win32: WideCharToMultiByte, MultiByteToWideChar o puede utilizar una biblioteca como libiconv

+1

En ese punto puede usar UTF-16 en lugar de UTF-8 si su OS lo entiende. –

+0

+1: wcout para wstring para wchar_t (principalmente UTF-16 de ventana), cout para cadena para char (Linux, UTF-8 de manera predeterminada) – rubenvb

+1

'wcin' y' wcout' no funcionan en Windows. – Philipp

0

Si tiene texto real (es decir, una cadena de caracteres lógicos), a continuación, insertar a las amplias corrientes en su lugar. Las secuencias amplias codificarán automáticamente sus caracteres para que coincidan con los bits esperados por la codificación de configuración regional. (Y si tiene bits codificados, las secuencias decodificarán los bits y luego volverán a codificarlos para que coincidan con la configuración regional).

Hay una solución menor si SABE que tiene bits codificados en UTF (es decir, una matriz de bits destinados a decodificarse en una cadena de caracteres lógicos) Y usted SABE que el objetivo de la secuencia de salida espera ese mismo formato de bit, entonces puede omitir los pasos de decodificación y recodificación y escribir() los bits como es. Esto solo funciona cuando sabe que ambas partes usan el mismo formato de codificación, lo que puede ser el caso de pequeñas utilidades que no están destinadas a comunicarse con procesos en otras configuraciones regionales.

+2

No hay codificación local en Windows y, por lo tanto, las transmisiones anchas no funcionan. – Philipp

6

Tuve un problema similar en el pasado, en mi caso imbue y sync_with_stdio hicieron el truco. Prueba esto:

#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

¿Hizo para probar este código? ¡Tengo un error de tiempo de ejecución! – Narek

+2

He depurado, las costuras esta línea es el problema: wcin.imbue (locale ("en_US.UTF-8")); – Narek

+1

@Narek Sí, probé el código. Se ejecuta sin problemas en mi Ubuntu. que sistema tienes? – Bolo