阅读了大约 30 分钟,并没有在本网站上找到一些具体的内容。
假设在 C# 中,控制台应用程序如下:
ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
Console.WriteLine(cki.KeyChar.ToString()); //Or Console.WriteLine(cki.KeyChar) as well
Console.ReadKey(true);
现在,让我们将 ¿
放在控制台条目中,并通过 Console.ReadKey(true)
将其分配给 cki
。将显示的不是 ¿
符号,而是显示的 ¨
符号。许多其他角色也会发生同样的情况。示例:ñ
显示 ¤
,¡
显示 -
,´
显示 ï
.
现在,让我们使用相同的代码片段并添加一些东西以获得更像 Console.ReadLine()
的行为:
string data = string.Empty;
ConsoleKeyInfo cki;
for (int i = 0; i < 10; i++)
{
cki = Console.ReadKey(true);
data += cki.KeyChar;
}
Console.WriteLine(data);
Console.ReadKey(true);
问题,如何以正确的方式处理这个问题,结束打印应该存储在 data
中的正确字符,而不是 ¨
、¤
、-
、ï
等?
请注意,我想要一个适用于 ConsoleKeyInfo
和 Console.ReadKey()
的解决方案,而不是使用其他变量类型或读取方法。
编辑:
因为来自 Console 命名空间的 ReadKey() 方法依赖于 Kernel32.dll,而且它在处理扩展的 ASCII 和 unicode 时肯定是错误的,因此不再是为它返回的内容找到有效转换的选项。
处理 ReadKey() 不良行为的唯一有效方法是使用在 cki = Console.ReadKey(true)
执行中编写的 cki.Key 属性并对其应用开关,然后,根据按下的键返回正确的值。
例如,要处理 Ñ
键按下:
string data = string.Empty;
ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
switch (cki.Key)
{
case ConsoleKey.Oem3:
if (cki.Modifiers.ToString().Contains("Shift")) //Could added handlers for Alt and Control, but not putted in here to keep the code small and simple
data += "Ñ";
else
data += "ñ";
break;
}
Console.WriteLine(data);
Console.ReadKey(true);
那么,现在这个问题有了更广泛的关注点……还有哪些其他函数只按下一个键就完成了它的执行,并返回按下的内容(代替 ReadKey())?我认为没有这样的替代品,但确认的答案会很有用。
最佳答案
问题不在于控制台不知道如何处理 Unicode(它知道,而且是正确的,check out this thread)。问题在于您对键盘上的按键、键码转换、键码转换为字符以及 ReadKey() 方法如何工作的理解。
首先:如果您想读取连续的字符,请改用 Console.ReadLine()
,它会为您完成所有数学运算,而且效果会更好。
让我们看一下下面的程序:
Console.WriteLine("Press a key to start (Enter to stop).");
var key = Console.ReadKey();
var allKeys = "";
while(key.Key != ConsoleKey.Enter)
{
Console.WriteLine(key.KeyChar);
allKeys += key.KeyChar;
key = Console.ReadKey();
}
它从输入中读取一个键,然后将它附加到字符串中。没什么好担心的,对吧?错误的!在美式国际键盘上,您可以这样做:
- 键入 ` + a 变成
à
- 键入 Alt+123 变为
{
- 键入 Alt+3355 变为 ←
- 输入;就像在西类牙语键盘上一样,变成 ñ
根据您的键盘,您会为特定字符按下不同的键。有时您会按下组合键。上面的第一个组合被记录为 \0a
作为字符串和键码 0
(不在枚举中),然后是 ConsoleKey.A
。总的结果字符串现在是 "\0á{←ñ"
。
Alt+123/3355 被记录为键码 18(这是 Alt 键)。数字键到字符的转换由操作系统在发送到控制台之前完成。
在美国键盘上键入 ;
或在西类牙键盘上键入 ñ
将显示 ConsoleKey.Oem1
(美国)和 ConsoleKey.Oem3
(西类牙语)。
虽然我无法模仿你的行为,这可能是因为我没有你的屏幕,但你作为控制台字体的字体似乎不支持非 Unicode 字符。在 Windows 7 上,默认情况下是这样,我不知道其他 Windows 版本。也有可能是您控制台的代码页设置不正确。
总结
字符的构成取决于键盘布局、国际设置中选择的键盘、选择的语言、控制台中选择的代码页以及是否允许组合键(使用 IME 会变得更糟!)。从 KeyChar 到普通字符通常是微不足道的,但取决于您的系统设置是否相互同步。
当我在我的系统上运行您的示例时,我没有相同的行为。但话又说回来,我没有你的系统。
从一个键变成一个角色是一件棘手的事情。我建议您不要依靠自己的能力来重新发明系统中已有的东西。尝试查看正在发生的事情是一种很好的做法,但实际上,请回到 ReadLine
;)。
编辑:
我刚看到你的最新编辑。请注意,您可以对输入和输出使用不同的编码(Console.InputEncoding
和 Console.OutputEncoding
)。我还想引用另一个线程来强调当您切换到 Unicode 时,代码页不再重要。这是最近 Windows 版本的默认行为:
If you select a Unicode font, such as Lucida Console or Consolas, then you will be able to see and type Unicode characters on the console, regardless of what chcp says:
关于c# - 使用 Console.ReadKey() 方法和 ConsoleKeyInfo 变量将扩展的 ASCII 字符转换为正确的表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9953936/