【问题标题】:Print and store spanish characters (á, é, í, ñ...) in cmd在 cmd 中打印和存储西班牙语字符(á、é、í、ñ...)
【发布时间】:2021-04-15 13:45:41
【问题描述】:

我正在使用带有 cmd 的带有 mingw-w64(gcc 版本 8.1.0,x86_64-posix-sjlj-rev0,由 MinGW-W64 项目构建)的 Microsoft Windows 10。当我尝试在 Windows 控制台上打印或存储然后打印西班牙语字符时,它显示错误。例如我试图执行这个程序:

#include <stdio.h>

int main(void) {
    char c[20];
    printf("pía\n");
    scanf("%s", c);
    printf("%s", c);
}

如果我引入一些西班牙语字符,返回的句子是可以的,但开头的打印显示错误:

pía
laíóñaú
laíóñaú

一些解决方案建议使用setlocale() 函数,但结果相同。其他解决方案是将 UTF-8 unicode 兼容性放在区域设置中:

但是现在错误是相反的,打印出来的还可以,但是当我引入一个奇怪的字符时,控制台没有显示它:

pía
lía
l

这有点令人沮丧,因为我看到的所有解决方案都是通过上述方法或通过设置setlocale() 解决的,但它们都不适合我,我不知道为什么。

编辑

正如 Mofi 在 cmets 中所说,我尝试使用 SetConsoleCP()SetConsoleOutputCP() 更改控制台的代码页。在没有完全理解这些函数是如何工作的情况下,使用与上面相同的代码,我运行了几个结果错误的示例:

pía                       | p├¡a                    | p├¡a                  | pía
lía                       | lía                     | lía                   | lía
l                         | l                       | lía                   | la
input: 65001 output 65001 | input: 65001 output 850 | input: 850 output 850 | input: 850 output 65001

我怎么不完全理解这个功能我不知道为什么在最后一个例子中,控制台没有显示重音存储字符,但在打印的那个中它显示了,而在上面的例子中发生了相反的情况。

【问题讨论】:

  • 我建议阅读 Microsoft 文档 Console Developer's Guide & API Reference 并在您的 C 编码应用程序中使用 Windows 控制台功能。 cmd.exe当前使用的code page根据为使用的账户配置的地区(国家)可以通过函数GetConsoleCP获取并通过SetConsoleCP设置。
  • GetConsoleCPSetConsoleCP 用于标准输入流。标准输出流的代码页可以用GetConsoleOutputCP 获取,用SetConsoleOutputCP 设置。两个流通常使用相同的代码页。我建议对西班牙语使用代码页 854 或 850。在 cmd 窗口中运行 chcp 时显示的计算机上帐户的默认代码页是哪个代码页?
  • 另请参阅 Microsoft 文档页面 Code Page Identifiers。我建议看Using another language (code page) in a batch file made for otherseryksun 写的cmets。最好不要使用 UTF-8 以最大限度地兼容旧的 Windows 版本(如 Windows 7/XP),并使用包含 Windows 控制台应用程序应支持的所有西班牙字符的 OEM 代码页。
  • 如果您只想通过文本编辑器使用代码页 Windows-1252 解决 pía 的输出最有可能使用字节流 70 ED 61 10 00(十六进制)编码的问题 你的C编译器,我建议使用printf("\x70\xA1\x61\n"); /* That is pía OEM 850 encoded. */根据OEM code page 850编译带有字节流70 A1 61 10 00的字符串,独立于文本编辑器使用哪个代码页,几乎独立于哪个字符编码C编译器使用。
  • 你必须先了解character encoding。另请参阅this page 上的介绍章节。您必须了解您输入的字符串如何与编辑器在 .c 源代码文件中的哪个字节流一起存储。接下来,您必须知道使用的 C 编译器在最终链接到可执行文件或库的目标文件中创建字符串的字节流时如何解释 .c 文件中的字符串字节。

标签: c windows winapi cmd windows-console


【解决方案1】:

正如Mofi 在上面的 cmets 中所说,解决方案在于我使用的编辑器如何解释我写的字符。我正在使用 Visual Studio Code 并更改默认提供的编码,在右下角将UTF-8更改为CP 850。现在编辑器将能够正确解释西班牙语字符。

下一个问题是更改控制台的代码页。使用命令chcp 850 或使用函数SetConsoleCP(850)SetConsoleOutputCP(850),我们可以更改我们打开的每个控制台上的代码页。要默认设置,请执行以下操作:

  • 打开注册表编辑器并转到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
  • New -> String Value并输入名称Autorun
  • 将值修改为chcp 850 &gt; nul

【讨论】:

    【解决方案2】:

    我玩了一段时间,唯一有效的是使用 _setmode() 设置 stdinstdout 以接收宽字符,然后使用 wchar_t 而不是 char存储文本。此代码在我的机器上按预期工作:

    #include <stdio.h>
    #include <fcntl.h>
    #include <io.h>
    
    int main(void) {
        _setmode(_fileno(stdin), _O_WTEXT);
        _setmode(_fileno(stdout), _O_WTEXT);
        wchar_t c[20];
        wprintf(L"pía\n");
        wscanf(L"%ls", c);
        wprintf(L"%ls", c);
    }
    

    已编辑:我将 _setmode 的参数从 _O_U16TEXT 更改为 _O_WTEXT 以避免由于 wchar_t 的长度是 2 或 4 字节而导致的实现问题,基于编译器。

    【讨论】:

    • 这可能是@Mofi 在最后一条评论中提出的解决方案,但正如我上面提到的,应该有一个更简单的解决方案来应用,不是吗?
    • 问题是scanf 没有按照文档接收 Unicode 流,因此您必须使用 wscanf 并设置标准 I/O 模式以接受宽字符。您可以将wchar_t 替换为char,但我认为这是不好的做法,因为一个char 不会对应于一个实际的Unicode 字符,并且您需要将数组的大小加倍。 @RafaHernández
    • 至少这样你就不必弄乱代码页和语言环境等等。
    猜你喜欢
    • 1970-01-01
    • 2017-07-04
    • 2012-07-14
    • 1970-01-01
    • 2014-11-30
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多