为了表示字符,您可以使用通用字符名称(UCN)。字符'ф'具有Unicode值U+0444,因此在C++中,您可以将其写为'\u0444'或'\U00000444'。此外,如果源代码编码支持此字符,则可以在源代码中直接按字面意义编写它。
// both of these assume that the character can be represented with
// a single char in the execution encoding
char b = '\u0444';
char a = 'ф'; // this line additionally assumes that the source character encoding supports this character
输出此类字符取决于你将要输出到哪里。如果你要输出到 Unix 终端仿真器,终端仿真器正在使用支持该字符的编码,并且该编码与编译器的执行编码相匹配,则可以执行以下操作:
#include <iostream>
int main() {
std::cout << "Hello, ф or \u0444!\n";
}
这个程序并不要求'ф'可以用单个字符表示。在OS X和大多数现代Linux安装中,这将完美运作,因为源代码、执行以及控制台编码都是UTF-8(支持所有Unicode字符)。
对于Windows来说,情况会更加复杂,因为有不同的可能性和权衡取舍。
如果你不需要可移植的代码(你将使用wchar_t,在其他平台上真的应该避免使用),最好的方法是将输出文件句柄的模式设置为只接受UTF-16数据。
#include <iostream>
#include <io.h>
#include <fcntl.h>
int main() {
_setmode(_fileno(stdout), _O_U16TEXT);
std::wcout << L"Hello, \u0444!\n";
}
可移植性代码更加困难。
char
。具体来说,它将是字节0xE4。请注意,我并不建议使用这样的执行字符集是一个好习惯,我只是在描述C++的工作原理。 - bames53\u
与使用\x
不同的原因。 - bames53当使用-std=c++11
进行编译时,可以简单地
const char *s = u8"\u0444";
cout << s << endl;
\uXXXX
和 \UXXXXXXXX
被称为通用字符名称。形如 u8"..."
的字符串字面值是UTF-8字符串字面值。两者均在标准中指定。 - ynn最终,这完全取决于平台。不幸的是,在标准的C++中,对Unicode的支持非常差。对于GCC编译器,你必须将其转换为窄字符串,因为它们使用UTF-8编码,而Windows需要宽字符串,并且必须输出到wcout
。
// GCC
std::cout << "ф";
// Windoze
wcout << L"ф";
\uXXXX
,其中 XXXX
代表 十六进制 数字。不幸的是,这会将 U+FFFF 之后的所有字符都排除在外。 - Mike DeSimone\u
实例来生成一个UTF-16代理对。 - Billy ONeal\UXXXXXXXX
。请注意,翻译没有添加任何解释或背景信息。 - bames53'\u0400'
是一个窄字符字面量。您似乎假设\u0400
存在于执行字符集中。根据N3242 [lex.ccon]/5的规定:“通用字符名将被翻译为所命名字符在适当执行字符集中的编码。如果没有这样的编码,则通用字符名将被翻译为实现定义的编码。” - curiousguy这段代码在Linux中运行良好(C++11,Geany和GCC 7.4 (g++
. 2018-12-06)):
#include <iostream>
using namespace std;
int utf8_to_unicode(string utf8_code);
string unicode_to_utf8(int unicode);
int main()
{
cout << unicode_to_utf8(36) << '\t';
cout << unicode_to_utf8(162) << '\t';
cout << unicode_to_utf8(8364) << '\t';
cout << unicode_to_utf8(128578) << endl;
cout << unicode_to_utf8(0x24) << '\t';
cout << unicode_to_utf8(0xa2) << '\t';
cout << unicode_to_utf8(0x20ac) << '\t';
cout << unicode_to_utf8(0x1f642) << endl;
cout << utf8_to_unicode("$") << '\t';
cout << utf8_to_unicode("¢") << '\t';
cout << utf8_to_unicode("€") << '\t';
cout << utf8_to_unicode("") << endl;
cout << utf8_to_unicode("\x24") << '\t';
cout << utf8_to_unicode("\xc2\xa2") << '\t';
cout << utf8_to_unicode("\xe2\x82\xac") << '\t';
cout << utf8_to_unicode("\xf0\x9f\x99\x82") << endl;
return 0;
}
int utf8_to_unicode(string utf8_code)
{
unsigned utf8_size = utf8_code.length();
int unicode = 0;
for (unsigned p=0; p<utf8_size; ++p)
{
int bit_count = (p? 6: 8 - utf8_size - (utf8_size == 1? 0: 1)),
shift = (p < utf8_size - 1? (6*(utf8_size - p - 1)): 0);
for (int k=0; k<bit_count; ++k)
unicode += ((utf8_code[p] & (1 << k)) << shift);
}
return unicode;
}
string unicode_to_utf8(int unicode)
{
string s;
if (unicode>=0 and unicode <= 0x7f) // 7F(16) = 127(10)
{
s = static_cast<char>(unicode);
return s;
}
else if (unicode <= 0x7ff) // 7FF(16) = 2047(10)
{
unsigned char c1 = 192, c2 = 128;
for (int k=0; k<11; ++k)
{
if (k < 6)
c2 |= (unicode % 64) & (1 << k);
else
c1 |= (unicode >> 6) & (1 << (k - 6));
}
s = c1;
s += c2;
return s;
}
else if (unicode <= 0xffff) // FFFF(16) = 65535(10)
{
unsigned char c1 = 224, c2 = 128, c3 = 128;
for (int k=0; k<16; ++k)
{
if (k < 6)
c3 |= (unicode % 64) & (1 << k);
else if
(k < 12) c2 |= (unicode >> 6) & (1 << (k - 6));
else
c1 |= (unicode >> 12) & (1 << (k - 12));
}
s = c1;
s += c2;
s += c3;
return s;
}
else if (unicode <= 0x1fffff) // 1FFFFF(16) = 2097151(10)
{
unsigned char c1 = 240, c2 = 128, c3 = 128, c4 = 128;
for (int k=0; k<21; ++k)
{
if (k < 6)
c4 |= (unicode % 64) & (1 << k);
else if (k < 12)
c3 |= (unicode >> 6) & (1 << (k - 6));
else if (k < 18)
c2 |= (unicode >> 12) & (1 << (k - 12));
else
c1 |= (unicode >> 18) & (1 << (k - 18));
}
s = c1;
s += c2;
s += c3;
s += c4;
return s;
}
else if (unicode <= 0x3ffffff) // 3FFFFFF(16) = 67108863(10)
{
; // Actually, there are no 5-bytes unicodes
}
else if (unicode <= 0x7fffffff) // 7FFFFFFF(16) = 2147483647(10)
{
; // Actually, there are no 6-bytes unicodes
}
else
; // Incorrect unicode (< 0 or > 2147483647)
return "";
}
更多:
如果您使用Windows (请注意,我们正在使用printf(),而不是cout):
// Save as UTF-8 without a signature
#include <stdio.h>
#include<windows.h>
int main (){
SetConsoleOutputCP(65001);
printf("ф\n");
}
虽然不是Unicode,但它可以工作——使用Windows-1251而不是UTF-8:
// Save as Windows 1251
#include <iostream>
#include<windows.h>
using namespace std;
int main (){
SetConsoleOutputCP(1251);
cout << "ф" << endl;
}
'1060'
是四个字符,在标准下无法编译。如果你的宽字符与Unicode一一对应(检查你的区域设置),你应该将字符视为数字。
int main (){
wchar_t f = 1060;
wcout << f << endl;
}
operator <<
来检测类型并执行正确的操作。但是似乎并不总是如此? - Mike DeSimone'1060'
是 C++ 标准下类型为 int
的多字符字面值,完全合法。但它的值是由实现定义的。大多数实现会将字符的值连接起来形成一个单一的整数值。这些有时被用于所谓的“FourCC”。 - bames53我需要在用户界面中显示字符串,并将其保存到 XML 配置文件中。上述指定的格式适用于 C++ 中的字符串,我想补充一下,我们可以通过将 "\u" 替换为 "&#x" 并在末尾添加一个 ";" 来获得与 XML 兼容的特殊字符的字符串。
举个例子:
C++: "\u0444" → XML: "ф"
std::cout
。即使这两个步骤都正确完成,正确显示字符在连接到std::cout
的任何内容中仍然是一个完全不同的问题。 - Luc Danton