提问人:Tomáš Zato 提问时间:6/19/2014 最后编辑:CommunityTomáš Zato 更新时间:6/19/2014 访问量:2079
如何在控制台中制作动态字符串以使用 UTF-8?
How can I make dynamic strings to work with UTF-8 in console?
问:
这里关于 SO 的大多数答案和问题都放在任何 UTF-8 字符串之前。我没有找到它是什么的解释,在源代码中,根据我的 IDE,常量在 .L
winnt.h
这就是我使用它的方式,不知道它是什么:
std::wcout<<L"\"Přetečení zásobníku\" is Stack overflow in Czech.";
显然,常量串联不能应用于变量:
void printUTF8(const char* str) {
//Does not make the slightest bit of sense
std::wcout<<L str;
}
那么它是什么以及如何将其添加到动态字符串中呢?
答:
L 是向 C 编译器指示字符串由“宽字符”组成的。在 Windows 中,这些是 UTF-16 - 您放入字符串中的每个字符都是 16 位或两个字节宽:
L"This is a wide string"
相比之下,UTF-8 字符串始终是由字节组成的字符串。ASCII 字符(A-Z、0-9 等)的编码方式一直如此 - 在 0x00 到 0x7F(或 0 到 127)的范围内。国际字符(如ř)使用0x80到0xFF范围内的多个字节进行编码 - 维基百科上有一个很好的解释。优点是可以使用普通的 C 字符串来表示。
"This is an ordinary string, but also a UTF-8 string"
"This is a C cedilla in UTF-8: \xc3\x87"
但是,如果您在实际代码中键入这些国际字符,则编辑器需要知道您键入的是 UTF-8,以便它可以正确编码字符 - 就像上面的 C cedilla 一样。然后,字符串将正确地传递给您的函数。
在您的情况下,您的注释表明您正在使用 UTF-16。在这种情况下,还有另外两个问题:
默认情况下,控制台将无法正确输出 Unicode 字符。您需要将字体更改为 truetype 字体,例如 Lucida Console
您还需要将输出模式更改为 Unicode UTF-16 模式。您可以通过以下方式执行此操作:
_setmode(_fileno(stdout), _O_U16TEXT);
代码示例:
#include <iostream>
#include <io.h>
#include <fcntl.h>
int wmain(int argc, wchar_t* argv[])
{
_setmode(_fileno(stdout), _O_U16TEXT);
std::wcout << L"Přetečení zásobníku is Stack overflow in Czech." << std::endl;
}
评论
_setmode
wcout
L""
是一个 WIDE 字符串。也就是说,它是一个.UTF-8 字符串不能很宽,因为它们是多字节(可变长度)的。VC++ 略有错误,使宽字符串可变长度,准确地说是 UTF-16。但通常它们是 UTF-32。wchar_t[1]
多字节字符串的问题在于有许多不同的编码,UTF-8 只是其中之一。事实上,Windows 本身并不支持 UTF-8 编码。 例如,可以使用除 UTF-8 以外的任何编码。只有一个例外,那就是你在这里需要的。MessageBoxA()
MultiByteToWideChar(CP_UTF8, ...)
评论
mbclen
strlen
wchar_t
wcslen
WCHAR
unsigned short
WCHAR
wchar_t
wchar_t
回复您的实际问题
“ 什么是[前缀]以及如何将其添加到动态字符串中?
L
这与我写这篇文章时的问题标题非常不同,即“如何制作动态字符串以在控制台中使用 UTF-8?
简而言之,UTF-8 是 Unicode 的一种编码,其中基本编码单元是 8 位,通常称为字节(更准确地说是八位字节),而前缀形成宽字符或字符串文字,其中编码单元通常为 16 或 32 位——在 Windows 中它是 16 位,就像原始 Unicode 一样。L
宽字符或字符串文本基于类型而不是 。wchar_t
char
在 Windows 中,宽字符串编码为 UTF-16。最常见的六万个左右的Unicode字符用单个值表示,但一些很少使用的中文表意文字等需要两个连续的值,称为代理项对。wchar_t
wchar_t
在 Windows 中使用 16 位编码单元是在 1992 年左右建立的。我不确定 UTF-16 是什么时候被采用的(作为当时的 UCS-2 编码的扩展),只是晚了一点。因此,早在 C99 要求宽字符集的所有字符都应用单个wchar_t
值表示之前,就已经确立了这一点。这一要求似乎是一种纯粹的政治策略,确保没有Windows C编译器可以正式符合,这是一种仅适用于Unix领域的通用ISO编程语言标准。不幸的是,由于 C++ 11 基于 C99,我们现在在 C++11 中也有它,确保没有 Windows C++ 编译器可以完全符合。纯粹的白痴。如果你问我。
勘误表,重新删除了上面的文字:根据维基百科关于它的文章,关于单个字符足以满足“扩展字符集”中任何字符的措辞在 C90 中已经存在。这使得Windows与C和C++标准之间的不兼容是Microsoft的错,而不是C委员会的错。它似乎仍然是政治性的,而且相当愚蠢,但(开明)其他人应该受到指责,而不是我最初坚持的......wchar_t
使用宽动态字符串的一种方法是使用 ,from the header。std::wstring
<string>
使用 Visual C++,您可以使用 wmain
函数而不是标准函数,作为获取宽命令行参数的简单方法。main
wmain
MinGW64 (IIRC) g++ 也支持,尽管普通 MinGW g++ 还不支持,但从 g++ 4.8.something 开始。但是,就 Windows API 而言,它很容易实现。除非你需要严格的符合标准的代码来提供特殊的主要功能特性,例如能够用或不带参数来声明它,但是嘿,让我们务实一点。
使用 Visual C++ 12.0 和 g++ 4.8.2 正常编译的示例:
// Source encoding: UTF-8 with BOM.
#include <io.h> // _setmode
#include <fcntl.h> // _O_WTEXT
#include <iostream> // std::wcout, std::endl
#include <string> // std::wstring
using namespace std;
auto main()
-> int
{
_setmode( _fileno( stdin ), _O_WTEXT );
_setmode( _fileno( stdout ), _O_WTEXT );
wcout << L"Hi, what’s your name? ";
wstring username;
getline( wcin, username );
wcout << L"Welcome to Windows C++, " << username << "!" << endl;
}
请注意,使用 Windows ANSI 源时,除非使用适当的编译器选项指定源编码,否则不会使用 g++ 进行编译。
上一个:C++ 控制台屏幕大小
评论