C - 如何正确读取stdin的本地化输入?

时间:2013-03-08 18:48:07

标签: c setlocale

我需要通过stdin输入特殊字符,这样做似乎有问题。我猜fgetws()不支持cp852(我操作系统的标准控制台代码页,Win 7 x64顺便说一句)。我应该使用cp1250还是别的什么?我尝试在cmd.exe中使用chcp 1250,但这只持续到我关闭命令提示符。我在Visual C上。

#include <stdio.h>
#include <locale.h>

int main()
{
    wchar_t query[64];
    setlocale(LC_ALL, "croatian");
    wprintf(L"Insert special characters: ");
    fgetws(query, 64, stdin);
    fputws(query, stdout);
    putchar('\n');
    return 0;
} 

Console output example

2 个答案:

答案 0 :(得分:2)

尝试在程序中修复错误的区域设置是错误的。您应该在您的环境中设置正确的区域设置,并在代码中使用此值,如:

setlocale(LC_ALL, "");

这就是man-page所说的:

  

在启动主程序时,选择便携式“C”语言环境    默认。通过调用:

,程序可以移植到所有语言环境      

setlocale(LC_ALL,“”);

编辑:

看一下你的最后一个截图给我看来,在阅读输入时似乎有些混乱。

案例1:(没有调用setlocale的那个人)

......似乎并不太有趣。在(默认)“C”语言环境中只包含字符U + 00-U + 7E,即使它似乎以产生正确的结果,这或多或少是垃圾输入 - 垃圾输出的情况。 值0x9F是代码页825(参见:http://de.wikipedia.org/wiki/Codepage_852)编码Unicode字符'LATIN SMALL LETTER C WITH CARON'(U + 010D)č

来回传递原始值,如果再次向终端写入相同的字节,则会产生相同的输出,这并不奇怪。

案例2:

......看起来更有趣。 值0x17a是unicode字符'LATIN SMALL LETTER Z WITH ACUTE'(U + 017A)ź的UTF-16编码,完全匹配截图中显示的输出。由于fputsw似乎在核心地将其映射到终端编码,因此问题似乎是输入未被正确读取。

只是为了确保在进行更改后没有任何困惑 - 你正在运行这样的代码吗?

#include <stdio.h>
#include <locale.h>

int main () {
    wchar_t query[64];
    setlocale (LC_ALL, "");

    if (fgetws(query, 64, stdin) == NULL)
      return -1;
    fputws(query, stdout);
    putchar('\n');

    return 0;
}

编辑:

区域设置检查

我忘了提及你测试中最有趣的事情之一:unicode字符'拉丁文小写字母带有急促'(U + 017A)ź(你的第二个截图中的一个输出)完全代表作为值0x9f(这是您在代码页1250中使用“原始”字符代码时报告的值)。

fgetws似乎使用代码页1250而不是代码页825来解释字符代码。

至于我,似乎问题仍然是区域设置以某种方式混淆了。您可能应该尝试运行以下代码并查看报告的区域设置。

#include <locale.h>
#include <stdio.h>

int main (int argc, char *argv[]) {
  char *locale;

  setlocale (LC_ALL, "");
  if ((locale = setlocale (LC_ALL, NULL)) == NULL)
    return -1;

  printf ("%s\n", locale);

  return 0;
}

在我的系统上,例如,这给出了输出:es_ES.utf8有趣的部分是点''后面的那个。因为它指定了字符编码(上面给出的例子中的utf8)。

要检查的另一件事可能是您正在使用的Visual Studio的程序版本,因为在旧版本中设置默认语言环境似乎存在错误。 (见:http://connect.microsoft.com/VisualStudio/feedback/details/709505/setlocale-lc-all-returns-incorrect-default-system-locale

答案 1 :(得分:0)

谢谢mikyra,试图提供帮助。 解决方法是将setlocale显式地作为第二个参数提供给我的控制台的默认代码页。像这样:

setlocale( LC_ALL, ".852" );

希望不会出现新问题。谢谢,MSDN