2012-02-29 21 views
12

Estoy tratando de leer cadena Unicode desde una consola en C#, por el bien de ejemplo, deja que su uset uno:lectura Unicode desde la consola

c: \ SVN \ D³ebugger \ src \ виталик \ Program.cs

al principio sólo trataron de Console.ReadLine() que me volvió c:\SVN\D3ebugger\src\???????\Program.cs

he tratado de establecer el Console.InputEncoding a UTF8 al igual que Console.InputEncoding = Encoding.UTF8 pero eso me volvieron c:\SVN\D³ebugger\src\???????\Program.cs, básicamente ensuciar la parte de la cadena cirílico .

Al azar tropezando He intentado configurar la codificación de esa manera, Console.InputEncoding = Encoding.GetEncoding(1251); que devolvió c:\SVN\D?ebugger\src\виталик\Program.cs, esta vez corrompiendo el carácter ³.

En este punto, parece que al cambiar encodings para InputStream, solo puedo obtener un idioma a la vez.

También he intentado ir nativo y hacer algo así:

// Code 
public static string ReadLine() 
{ 
    const uint nNumberOfCharsToRead = 1024; 
    StringBuilder buffer = new StringBuilder(); 

    uint charsRead = 0; 
    bool result = ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buffer, nNumberOfCharsToRead, out charsRead, (IntPtr)0); 

    // Return the input minus the newline character 
    if (result && charsRead > 1) return buffer.ToString(0, (int)charsRead - 1); 
    return string.Empty; 
} 

// Extern definitions 

    [DllImport("Kernel32.DLL", ExactSpelling = true)] 
    internal static extern IntPtr GetStdHandle(int nStdHandle); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] 
    static extern bool ReadConsoleW(IntPtr hConsoleInput, [Out] StringBuilder lpBuffer, 
     uint nNumberOfCharsToRead, out uint lpNumberOfCharsRead, IntPtr lpReserved); 

que estaba trabajando bien para las cadenas no Unicode, sin embargo, cuando traté de hacer que lee mi cadena de ejemplo, se bloqueó la aplicación . Intenté decirle a Visual Studio que rompa TODAS las excepciones (incluidas las nativas), pero la aplicación aún se bloqueará.

También encontré this error de apertura en Microsoft Connect que parece indicar que ahora es imposible leer Unicode desde el InputStream de la consola.

Vale la pena señalar, aunque no está estrictamente relacionado con mi pregunta, que Console.WriteLine puede imprimir esta cadena muy bien, si Console.OutputEncoding está configurado en UTF8.

¡Gracias!

Actualización 1

Busco a una solución para .NET 3.5

Actualización 2

Actualizado con el código nativo completo que he usado.

+0

¿Es posible/aceptable el uso de una tubería con nombre en lugar de la consola? – Goyuix

+0

Si no encuentro una solución, probablemente sea eso lo que haré ... – VitalyB

Respuesta

6

Aquí está una versión totalmente funcional en .NET 3.5 Cliente:

class Program 
{ 
    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern IntPtr GetStdHandle(int nStdHandle); 

    [DllImport("kernel32.dll")] 
    static extern bool ReadConsoleW(IntPtr hConsoleInput, [Out] byte[] 
    lpBuffer, uint nNumberOfCharsToRead, out uint lpNumberOfCharsRead, 
    IntPtr lpReserved); 

    public static IntPtr GetWin32InputHandle() 
    { 
    const int STD_INPUT_HANDLE = -10; 
    IntPtr inHandle = GetStdHandle(STD_INPUT_HANDLE); 
    return inHandle; 
    } 

    public static string ReadLine() 
    { 
    const int bufferSize = 1024; 
    var buffer = new byte[bufferSize]; 

    uint charsRead = 0; 

    ReadConsoleW(GetWin32InputHandle(), buffer, bufferSize, out charsRead, (IntPtr)0); 
    // -2 to remove ending \n\r 
    int nc = ((int)charsRead - 2) * 2; 
    var b = new byte[nc]; 
    for (var i = 0; i < nc; i++) 
     b[i] = buffer[i]; 

    var utf8enc = Encoding.UTF8; 
    var unicodeenc = Encoding.Unicode; 
    return utf8enc.GetString(Encoding.Convert(unicodeenc, utf8enc, b)); 
    } 

    static void Main(string[] args) 
    { 
    Console.OutputEncoding = Encoding.UTF8; 
    Console.Write("Input: "); 
    var st = ReadLine(); 
    Console.WriteLine("Output: {0}", st); 
    } 
} 

enter image description here

+0

Cambiar bufferSize en ReadLine() si necesita grandes cadenas. Observe que el búfer tomará ** dos veces ** tantos bytes como caracteres. Además, si no le importa usar Linq, puede usar: 'var b = buffer.Take (nc) .ToArray();' en lugar de ese feo bucle For. – Jcl

+0

Funcionó muy bien, ¡gracias! Sin embargo, hice algo muy similar (usando ReadConsoleW) que no funcionaría en absoluto. Comprobaré lo que hice mal y lo actualizaré. – VitalyB

+0

Probablemente no se haya convertido a UTF8 después. Probablemente la entrada fue correcta, pero la salida no fue (simplemente adivinar) – Jcl

10

Esto parece funcionar bien cuando apuntan a .NET 4 perfil de cliente, pero por desgracia no cuando apuntan a .NET 3.5 perfil de cliente. Asegúrese de cambiar la fuente de la consola a Lucida Console.
Como lo señala @jcl, aunque he apuntado a .NET4, esto es solo porque tengo .NET 4.5 instalado.

class Program 
{ 
    private static void Main(string[] args) 
    { 
     Console.InputEncoding = Encoding.Unicode; 
     Console.OutputEncoding = Encoding.Unicode; 

     while (true) 
     { 
      string s = Console.ReadLine(); 

      if (!string.IsNullOrEmpty(s)) 
      { 
       Debug.WriteLine(s); 

       Console.WriteLine(s); 
      } 
     } 
    } 
} 

enter image description here

+0

¿Está usted en .NET 4.5, quizás? No funciona en .NET 4.0. La línea 'Consola.InputEncoding = Encoding.Unicode; 'lanza una excepción:" IOException - El parámetro es incorrecto. " – VitalyB

+0

Tengo VS 11 beta y .NET 4.5 beta instalados. Sin embargo, la aplicación de la consola funciona con VS 2010 y el perfil de cliente .NET 4. Estoy usando Windows 7 x64 SP1. – Phil

+0

Puedo confirmar que recibo la misma excepción que al apuntar al perfil del cliente .NET 3.5. – Phil

Cuestiones relacionadas