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

标签 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);

现在,让我们将 ¿ 放在控制台条目中,并通过 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 中的正确字符,而不是 ¨¤ -ï 等?

请注意,我想要一个适用于 ConsoleKeyInfoConsole.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.InputEncodingConsole.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/

相关文章:

console - Chrome DevTools 中的 == $0 是什么意思?

ruby-on-rails - Rails 控制台可以重新加载 lib 下的模块吗?

java - System.out.println() 的 JUnit 测试

c# - 如何终止 session 或 session ID (ASP.NET/C#)

c# - 双击以在WP8中缩放图像?

c# - ASMX文件下载

javascript - 删除javascript中的全 Angular 和半 Angular 字符

javascript - 为什么 Javascript 中的 charCodeAt 的行为似乎与 PHP 的 chr 不同?我正在尝试实现 base64

c++ - Clang 格式不正确的字符编码问题

c# - 使用 Protobuf-net 序列化 MultiValueDictionary(string,string) 时出错