【问题标题】:How to write Cyrillic text in C++ console如何在 C++ 控制台中编写西里尔文文本
【发布时间】:2021-12-30 23:38:45
【问题描述】:

例如,如果我写:

cout << "Привет!" << endl; //it's hello in Russian

在控制台中类似于╧ЁштхЄ!

好的,我知道我们可以使用:

setlocale(LC_ALL, "Russian");

但在那之后,俄语中的命令行参数不起作用(如果我通过 BAT 文件启动我的程序):

StartProgram.bat

chcp 1251
MyProgram.exe -user=Олег -password=Пароль

所以,在setlocale 之后,程序无法正确读取俄语参数。

这是因为 BAT 文件在 CP1251 中,但控制台在 CP866 中。

那么,有一个问题:

如何在 C++ 控制台中编写俄语文本,同时正确读取俄语命令行参数。

【问题讨论】:

    标签: c++ encoding character-encoding


    【解决方案1】:

    查看 Michael Kaplan 博客中的此条目:

    http://www.siao2.com/2008/03/18/8306597.aspx

    【讨论】:

    • 谢谢,它有效!但是这样我就不能用cout了,只能用wprintf
    • wcout 相当于 wprintf 就像 cout 相当于 printf - 最后两个不会做 Unicode。
    【解决方案2】:

    您是否尝试过使用wcout?它类似于cout,但它接受“宽”字符,这应该允许正确的 unicode 编码。

    来自 MSDN 的 article about localizationanother 可能有用。

    【讨论】:

    • 除非我完全弄错了,否则 unicode 将是西里尔文的必需品。常规 8 位 ASCII 没有西里尔字母中的大多数字符的字形。您的示例 (╧ЁштхЄ) 的控制台输出由一些特殊的 8 位 ASCII 字符组成,因为该编码中没有正确的字符。
    • 嗯.. Windows 西里尔字母是 1251 (Windows-1251) 代码页。但是 DOS 西里尔文使用 866 代码页。所以,“Привет!”在 CP1251 = “╧ЁштхЄ!”在 CP866 中。这就是发生的事情,我用 C++ 编写为 cp1251,但控制台显示为 cp866。
    • 啊,字符编码的乐趣:)
    • 不要忘记如果您使用 wcout 将 L 放在所有文字前面。因此,wcout &lt;&lt; L"Привет!" &lt;&lt; endl; 在您的示例中。
    • 谢谢,但这也不起作用,我想是因为我不使用 Unicode
    【解决方案3】:

    控制台设置为 1251 而不是 866:

     //Save As Windows 1251
        #include<stdio.h>
        #include<windows.h>
        int main(int argc, char **argv){ 
            SetConsoleOutputCP(1251);
            SetConsoleCP(1251);
            if(argc<2)return 0;
            else printf("Hello %s %s\n",argv[1],argv[2]);
        } 
    

    程序是argument.exe和结果:

    D:\Debug>参数 Олег Пароль
    你好 Олег Пароль

    【讨论】:

    • 代码文件也应该保存在 Cyrillic (Windows) Codepage (1251) 中。
    【解决方案4】:

    您是否在控制面板的区域和语言选项部分将非 unicode 程序的语言设置为俄语?

    (我不知道讲俄语的程序员通常的设置可能是什么;我只是想知道将其设置为某种英语以避免混淆过于狭隘的工具是否很常见。)

    除非我的记忆在开玩笑,否则当我使用来自日本开发人员的一些代码时,正是这一步让控制台正确显示了非 Unicode 日文文本(Shift-JIS 编码)。

    【讨论】:

      【解决方案5】:

      您可以尝试使用以下函数setlocale()SetConsoleOutputCP()

      setlocale(LC_ALL, "Russian");
      SetConsoleOutputCP(866);
      

      【讨论】:

      • 这个对我帮助很大。我们还需要添加一个 - 您应该使用 #include &lt;locale&gt;
      【解决方案6】:

      WriteConsoleW 可以处理 UNICODE,例如西里尔字母没有问题。如果您不会错过 wcout 的格式化功能,您可以重定向标准的 wcout 流缓冲区并使用 WriteConsoleW 打印它。

      A full example is shown here

      // save and redirect cout buffer
      wostringstream  newCoutBuffer;
      wstreambuf*     oldCoutBuffer = wcout.rdbuf(newCoutBuffer.rdbuf());    
      
      // do your wcout stuff here
      // do your wcout stuff here
      
      DWORD dwWritten;
      WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), newCoutBuffer.str().c_str(),newCoutBuffer.tellp(),&dwWritten,NULL);  
      
      // restore cout buffer
      wcout.rdbuf(oldCoutBuffer);
      

      【讨论】:

        【解决方案7】:

        对我来说,这似乎解决了问题:

        #include <fcntl.h>
        #include <io.h>
        #include <iostream>
        
        using namespace std;
        
        int main(void) {
            _setmode(_fileno(stdout), _O_U16TEXT);
            wcout << L"Огњен" << endl;
            return 0;
        }
        

        【讨论】:

          【解决方案8】:

          最正确的方法是使用 wcout + std::imbue。

          但是应该知道在 Windows Vista/7 中发生了 setlocale API 的一些变化。 “俄语”语言环境字符串不再被识别为“cp866”,至少在 Visual C++ CRT 中是这样。

          要获得 cp866 输出,请尝试改用:

          ::setlocale( LC_ALL , "russian_russia.866" );
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-29
            相关资源
            最近更新 更多