Чтение юникода с консоли - PullRequest
       23

Чтение юникода с консоли

14 голосов
/ 29 февраля 2012

Я пытаюсь прочитать строку Unicode из консоли в C #, например, давайте использовать его:

C: \ SVN \ D³ebugger \ SRC \ виталик \ Program.cs

Сначала я просто попытался Console.ReadLine(), который вернул мне c:\SVN\D3ebugger\src\???????\Program.cs

Я пытался установить для Console.InputEncoding значение UTF8, например, Console.InputEncoding = Encoding.UTF8, но это вернуло меня c:\SVN\D³ebugger\src\???????\Program.cs, в основном путая кириллическую часть строки.

Так беспорядочно спотыкаясь, я попытался установить кодировку следующим образом: Console.InputEncoding = Encoding.GetEncoding(1251);, которая вернула c:\SVN\D?ebugger\src\виталик\Program.cs, на этот раз искажая символ ³.

На данный момент кажется, что переключая кодировки для InputStream, я могу получить только один язык за раз.

Я также пытался перейти на родной язык и сделать что-то подобное:

// 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);

Это работало нормально для строк, не относящихся к юникоду, однако, когда я попытался заставить его прочитать мою строку-образец, приложение зависло. Я пытался сказать Visual Studio, чтобы он прерывался на ВСЕХ исключениях (включая собственные), но приложение все равно зависало.

Я также обнаружил эту открытую ошибку в Microsoft Connect, которая, кажется, говорит, что сейчас невозможно прочитать Unicode из InputStream консоли.

Стоит отметить, хотя Console.WriteLine, хотя и не относится строго к моему вопросу, может нормально печатать эту строку, если для Console.OutputEncoding задано значение UTF8.

Спасибо!

Обновление 1

Я ищу решение для .NET 3.5

Обновление 2

Обновлено с полным исходным кодом, который я использовал.

Ответы [ 2 ]

11 голосов
/ 04 марта 2012

Кажется, что это нормально работает при настройке профиля клиента .NET 4, но, к сожалению, не при настройке профиля клиента .NET 3.5. Убедитесь, что вы изменили шрифт консоли на Lucida Console.
Как отмечает @jcl, хотя я и настроил таргетинг на .NET4, это только потому, что у меня установлен .NET 4.5.

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

6 голосов
/ 09 марта 2012

Вот одна полностью рабочая версия клиента .NET 3.5:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...