如何在 C++ 控制台中编写西里尔文文本
Posted
技术标签:
【中文标题】如何在 C++ 控制台中编写西里尔文文本【英文标题】:How to write Cyrillic text in C++ console 【发布时间】:2010-02-14 15:03:44 【问题描述】:例如,如果我写:
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++ 控制台中编写俄语文本,同时正确读取俄语命令行参数。
【问题讨论】:
【参考方案1】:查看 Michael Kaplan 博客中的此条目:
http://www.siao2.com/2008/03/18/8306597.aspx
【讨论】:
谢谢,它有效!但是这样我就不能用cout了,只能用wprintfwcout
相当于 wprintf
就像 cout
相当于 printf
- 最后两个不会做 Unicode。【参考方案2】:
您是否尝试过使用wcout
?它类似于cout
,但它接受“宽”字符,这应该允许正确的 unicode 编码。
来自 MSDN 的 article about localization 和 another 可能有用。
【讨论】:
除非我完全弄错了,否则 unicode 将是西里尔文的必需品。常规 8 位 ASCII 没有西里尔字母表中大多数字符的字形。您的示例 (╧ЁштхЄ
) 的控制台输出由一些特殊的 8 位 ASCII 字符组成,因为该编码中没有正确的字符。
嗯.. Windows 西里尔字母是 1251 (Windows-1251) 代码页。但是 DOS 西里尔文使用 866 代码页。所以,“Привет!”在 CP1251 = “╧ЁштхЄ!”在 CP866 中。这就是发生的事情,我用 C++ 编写为 cp1251,但控制台显示为 cp866。
啊,字符编码的乐趣:)
不要忘记如果您使用 wcout 将 L
放在所有文字前面。因此,wcout << L"Привет!" << 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】:您可以尝试使用以下函数setlocale()
和SetConsoleOutputCP()
setlocale(LC_ALL, "Russian");
SetConsoleOutputCP(866);
【讨论】:
这个对我帮助很大。我们还需要添加一个 - 您应该使用#include <locale>
【参考方案5】:
您是否在控制面板的区域和语言选项部分将非 unicode 程序的语言设置为俄语?
(我不知道说俄语的程序员通常的设置可能是什么;我只是想知道将其设置为某种英语以避免混淆过于狭隘的工具是否很常见。)
除非我的记忆在开玩笑,否则当我使用来自日本开发人员的一些代码时,正是这一步让控制台正确显示了非 Unicode 日文文本(Shift-JIS 编码)。
【讨论】:
【参考方案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" );
【讨论】:
以上是关于如何在 C++ 控制台中编写西里尔文文本的主要内容,如果未能解决你的问题,请参考以下文章
如何防止在 Docker 容器中运行的 bash 中扭曲西里尔文文本?
如何在 PhpMyAdmin 中将 csv-import 西里尔文文本导入 latin1-swedish-ci 编码表?
React 组件中的 JSX 将西里尔文文本显示为 habra-codabra