2012-02-29 32 views
12

Tôi cố gắng để đọc chuỗi unicode từ một giao diện điều khiển trong C#, vì lợi ích của ví dụ, cho phép uset mình một:Reading unicode từ console

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

Lúc đầu, tôi chỉ cố gắng để Console.ReadLine() đó trở tôi c:\SVN\D3ebugger\src\???????\Program.cs

tôi đã cố gắng để thiết lập các Console.InputEncoding để UTF8 như vậy Console.InputEncoding = Encoding.UTF8 nhưng đó quay trở lại tôi c:\SVN\D³ebugger\src\???????\Program.cs, về cơ bản mucking lên phần Cyrillic của chuỗi .

Vì vậy, ngẫu nhiên tôi đã cố gắng đặt mã hóa như vậy, Console.InputEncoding = Encoding.GetEncoding(1251); trả lại c:\SVN\D?ebugger\src\виталик\Program.cs, lần này làm hỏng ký tự ³.

Tại thời điểm này có vẻ như bằng cách chuyển đổi encodings cho InputStream, tôi chỉ có thể nhận được một ngôn ngữ duy nhất tại một thời điểm.

Tôi cũng đã thử đi bản địa và làm một cái gì đó như thế:

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

Đó đã làm việc tốt cho các chuỗi không unicode, tuy nhiên, khi tôi đã cố gắng để làm cho nó đọc chuỗi mẫu của tôi, các ứng dụng bị rơi . Tôi đã cố gắng để nói với Visual Studio để phá vỡ tất cả ngoại lệ (bao gồm cả những người bản xứ), được nêu ra, ứng dụng sẽ vẫn sụp đổ.

Tôi cũng đã tìm thấy lỗi this lỗi mở trong Kết nối của Microsoft có vẻ như là không thể đọc ngay từ đầu vào của bảng điều khiển. Điều này đáng chú ý, mặc dù không liên quan chặt chẽ đến câu hỏi của tôi, rằng Console.WriteLine có thể in chuỗi này tốt, nếu Console.OutputEncoding được đặt thành UTF8.

Cảm ơn bạn!

Cập nhật 1

Tôi đang tìm kiếm một giải pháp cho .NET 3.5

Cập nhật 2

cập nhật với mã nguồn gốc đầy đủ Tôi đã sử dụng.

+0

Có thể/có thể chấp nhận sử dụng một ống tên thay cho giao diện điều khiển? – Goyuix

+0

Nếu tôi không tìm thấy giải pháp thì đó có thể là những gì tôi sẽ làm ... – VitalyB

Trả lời

6

Dưới đây là một phiên bản hoàn toàn làm việc trong .NET 3.5 Chủ đầu tư:

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

Thay đổi bufferSize trong ReadLine() nếu bạn cần các chuỗi lớn. Lưu ý rằng bộ đệm sẽ mất ** gấp đôi ** byte nhiều ký tự. Ngoài ra, nếu bạn không quan tâm đến việc sử dụng LINQ, bạn có thể sử dụng: 'var b = buffer.Take (nc) .ToArray();' thay vì vòng lặp for ugly For. – Jcl

+0

Nó hoạt động rất tốt, cảm ơn! Mặc dù, tôi đã làm một cái gì đó rất giống nhau (bằng cách sử dụng ReadConsoleW) mà sẽ không làm việc ở tất cả. Tôi sẽ kiểm tra những gì tôi đã làm sai và cập nhật. – VitalyB

+0

Có thể bạn đã không chuyển sang UTF8 sau đó. Có lẽ đầu vào là ok, nhưng đầu ra là không (chỉ đoán) – Jcl

10

Điều này có vẻ hoạt động tốt khi nhắm mục tiêu cấu hình ứng dụng .NET 4, nhưng tiếc là không phải khi định cấu hình lược tả khách hàng .NET 3.5. Đảm bảo bạn thay đổi phông chữ bảng điều khiển thành Bảng điều khiển Lucida.
Như được chỉ ra bởi @jcl, mặc dù tôi đã nhắm mục tiêu .NET4, điều này chỉ vì tôi đã cài đặt .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

+0

Bạn có đang sử dụng .NET 4.5 không? Nó không hoạt động trong .NET 4.0. Dòng lệnh 'Console.InputEncoding = Encoding.Unicode; 'ném một ngoại lệ:" IOException - Tham số không đúng. " – VitalyB

+0

Tôi đã cài đặt phiên bản VS 11 beta và .NET 4.5 beta. Tuy nhiên ứng dụng giao diện điều khiển hoạt động bằng cách sử dụng hồ sơ khách hàng VS 2010 và .NET 4. Tôi đang sử dụng Windows 7 x64 SP1. – Phil

+0

Tôi có thể xác nhận rằng tôi nhận được cùng một ngoại lệ như khi bạn định cấu hình lược tả ứng dụng .NET 3.5. – Phil

Các vấn đề liên quan