我正在尝试从 C# 控制台读取 unicode 字符串,为了举例,让我们使用他的一个:
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
,这次破坏了 ³ 字符。
此时看来,通过切换输入流的编码,我一次只能获得一种语言。
我也尝试过本地化并做类似的事情:
// 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);
这对于非 unicode 字符串工作得很好,但是,当我尝试让它读取我的示例字符串时,应用程序崩溃了。我试图告诉 Visual Studio 在所有异常(包括本机异常)时中断,但是应用程序仍然会崩溃。
我还发现了 this Microsoft Connect 中的开放错误,似乎表明现在不可能从控制台的 InputStream 读取 Unicode。
值得注意的是,即使与我的问题不严格相关,如果 Console.OutputEncoding 设置为 UTF8,Console.WriteLine 也能够很好地打印此字符串。
谢谢!
我正在寻找 .NET 3.5 的解决方案
更新了我使用过的完整本机代码。
在针对 .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);
}
}
}
}
这是 .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);
}
}
对于 .NET Core,我已成功使用此变体(一次将一个按键读取为 Unicode 字符):
string ReadLineUnicode()
{
StringBuilder sb = new StringBuilder();
ConsoleKeyInfo keyInfo;
while (true)
{
keyInfo = Console.ReadKey();
if (keyInfo.Key == ConsoleKey.Enter)
break;
sb.Append(keyInfo.KeyChar);
}
return sb.ToString();
}