使用Console.ReadKey()方法和ConsoleKeyInfo变量将扩展的ASCII字符转换为正确的表示

时间:2012-03-31 07:26:09

标签: c# encoding console ascii decoding

花了大约30分钟,并没有在这个网站找到一些特定的。

假设以下内容,在C#中,控制台应用程序:

ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
Console.WriteLine(cki.KeyChar.ToString()); //Or Console.WriteLine(cki.KeyChar) as well
Console.ReadKey(true);

现在,让我们将¿放入控制台条目,并通过cki将其与Console.ReadKey(true)对齐。将显示的不是¿符号,¨符号是显示的符号。许多其他角色也是如此。示例:ñ显示¤¡显示-´显示ï

现在,让我们使用相同的代码snipplet并为更多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上的正确字符,而不是¨¤,{{1} },-等?

请注意,我想要一个适用于ïConsoleKeyInfo的解决方案,而不是使用其他变量类型或读取方法。

编辑:

因为来自Console命名空间的ReadKey()方法依赖于Kernel32.dll,并且它定义性地处理扩展的ASCII和unicode,所以它不再是一个选项,只能找到它返回的有效转换。

处理ReadKey()的不良行为的唯一有效方法是使用在Console.ReadKey()执行中编写的cki.Key属性并对其应用切换,然后根据什么返回正确的值钥匙被按下了。

例如,要按cki = Console.ReadKey(true)键来处理:

Ñ

所以,现在问题有一个更广泛的焦点...其他功能只有一个键按下完成它的执行,并返回被按下的内容(ReadKey()的替代品)?我认为没有这样的替代品,但确认的答案将是有用的。

2 个答案:

答案 0 :(得分:1)

问题不在于控制台不知道如何处理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键)。将数字键转换为字符是由OS在发送到控制台之前完成的。

在美国键盘上键入;或在西班牙语键盘上键入ñ会向您显示ConsoleKey.Oem1(美国)和ConsoleKey.Oem3(西班牙语)。

虽然我无法模仿你的行为,但这可能是因为我没有你的屏幕,但是看起来很像你作为Console字体的字体不支持非Unicode字符。在Windows 7上,默认情况下,我不知道其他Windows版本。控制台的代码页也可能设置错误。

总结
角色的构成取决于键盘布局,国际设置中选定的键盘,所选语言,控制台中选定的代码页以及是否允许组合键(IME会变得更糟!)。从KeyChar转到普通字符通常很简单,但取决于您的系统设置是否彼此同步。

当我在我的系统上运行您的示例时,我没有相同的行为。但话说回来,我没有你的系统。

从钥匙转到角色是一件棘手的事。我建议你不要依靠自己的能力来重新发明系统中已有的东西。尝试查看正在发生的事情是一种很好的做法,但实际上,请回到ReadLine;)。

修改
我刚看到你最新的编辑。请注意,您可以对输入和输出(Console.InputEncodingConsole.OutputEncoding)进行不同的编码。我还想引用另一个帖子来强调,当你切换到Unicode时,代码页就不再重要了。这是最近Windows版本的默认行为:

  

如果您选择Unicode字体,例如Lucida Console或Consolas,那么   您将能够在控制台上查看和键入Unicode字符,   不管chcp说什么:

答案 1 :(得分:0)

ReadLine()重新配置代码页以正确使用扩展的ASCII和Unicode字符。 ReadKey()将其保留为EN-US默认值(代码页850)。

只需使用打印所需字符的代码页,即可。有关其中一些内容,请参阅http://en.wikipedia.org/wiki/Code_page:)

因此,对于Ñ按键,解决方法是:

Console.OutputEncoding = Encoding.GetEncoding(1252); //Also 28591 is valid for `Ñ` key, and others too
string data = string.Empty;
ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
data += cki.KeyChar;
Console.WriteLine(data);
Console.ReadKey(true);

简单:)

并附注:在某些情况下,还需要重新配置Console.InputEncoding属性!

另请注意,如果您为控制台选择另一种字体(Lucida Console / Consolas),则会出现此问题。 Lotta感谢用户Abel的这一点,他指定改变解决方案的字体并让我自己发现这是false