我希望我的程序尽可能便携。我在字符串中搜索重音字符,例如è。这可能是个问题吗?是否有与HTML实体相当的C ++?
它将在switch语句中使用,例如:
switch(someChar) //someChar is of type char
{
case 'é' :
x = 1;
break;
case 'è' :
...
}
答案 0 :(得分:11)
在C ++源代码中使用非ASCII字符的主要问题是编译器必须知道用于源的编码。如果源是7位ASCII,则通常不重要,因为大多数编译器默认采用ASCII兼容编码。
并非所有编译器都可以配置编码,因此两个编译器可能无条件地使用不兼容的编码,这意味着使用非ASCII字符可能导致无法同时使用的源代码。
因此,如果搜索的字符串是UTF-8(可能是因为执行字符集是UTF-8),请考虑使用代码搜索重音字符会发生什么。无论字符文字“é”是否按预期工作,您都不会找到重音字符,因为重音字符不会被任何单个字节表示。相反,您必须搜索各种字节序列。
C ++允许在字符和字符串文字中使用不同类型的转义。通用字符名称允许您指定Unicode代码点,并且将完全像在源中出现该字符一样处理。例如\u00E9
或\U000000E9
。
(其他一些语言\u
支持最高达U + FFFF的代码点,但缺少C ++对代码点的支持或者使用代理代码点。你不能在C ++中使用代理代码点而是C ++有\ U变体直接支持所有代码点。)
UCN也应该在字符和字符串文字之外工作。在这些文字之外,UCN仅限于不在基本源字符集中的字符。但是,直到最近编译器还没有实现这个(C ++ 98)功能。现在Clang似乎得到了相当完整的支持,MSVC似乎至少得到了部分支持,而GCC声称通过选项-fextended-identifiers
提供实验支持。
回想一下,UCN应该与源中出现的实际角色完全相同;因此,具有良好UCN标识符支持的编译器还允许您使用实际字符简单地编写标识符,只要编译器的源编码首先支持该字符。
C ++还支持十六进制转义。这些是\ x后跟任意数量的十六进制数字。十六进制转义将表示单个整数值,就好像它是具有该值的单个代码点,并且不对该值执行到执行字符集的转换。如果您需要表示独立于编码的特定字节(或char16_t,或char32_t或wchar_t)值,那么这就是您想要的。
还有八元逃逸,但它们不像UCN或十六进制逃脱那样常用。
以下是Clang在使用ISO-8859-1或cp1252编码的源文件中使用“é”时显示的诊断信息:
warning: illegal character encoding in character literal [-Winvalid-source-encoding]
std::printf("%c\n",'<E9>');
^
Clang仅将此问题作为警告发出,并直接输出具有源字节值的char对象。这样做是为了向后兼容非UTF-8源代码。
如果您使用UTF-8编码的源,那么您可以得到:
error: character too large for enclosing character literal type
std::printf("%c\n",'<U+00E9>');
^
Clang检测到UTF-8编码对应于Unicode代码点U + 00E9,并且此代码点超出了单个字符可以容纳的范围,因此报告错误。 (Clang也逃脱了非ascii字符,因为它确定它运行的控制台无法处理打印非ascii字符)。
答案 1 :(得分:8)
正式C ++甚至在标识符中也支持相当好的Unicode子集,因此理论上可以用例如标识符编写标识符。挪威字符,例如antallBlåbærsyltetøyGlass
。
实际上,C ++实现仅在标识符中支持A槽Z,数字0到9和下划线。一些实现还允许美元符号$。但是,该标准不允许美元符号。
要在文本文字中指定Unicode字符,您可以使用通用字符名称,它根本不是名称,而更像是转义序列,例如\u20AC
(欧元符号€)。如果将源代码保存为UTF-8,也可以直接编写此类字符。请注意,Visual C ++需要BOM(字节顺序标记)才能识别UTF-8源代码。
如果您将字符串视为UTF-8编码(即char
类型,如* nix中常见的那样)那么“é”(在ASCII范围0 ... 127之外)将不会是单char
个值,因此不能用作case
中的switch
标签。
但是,这个特殊字符是Latin-1的一部分,它是Windows ANSI Western的一个子集,它是一个每字符一个字节的编码。因此,在Windows的Western安装中,对字符串值使用ANSI编码,它是单个值,可以这样使用。 Latin-1也是Unicode的一个子集(包括Unicode的前256个代码点),因此基于wchar_t
的字符串,例如, std::wstring
,并且使用Unicode作为宽字符串,“é”也是单个值,即与Latin-1和Windows ANSI Western中的值相同。
尽管如此,使用wchar_t
表示Unicode并不能保证任何任意字符都是单个值。
例如,在Windows中,wchar_t
仅为16位,标准编码为UTF-16,其中所谓的基本多语言平面之外的字符(原始的16位Unicode )用两个称为代理对的值表示。更糟糕的是,即使使用UTF-32,Unicode也允许用两个或多个值表示重音字符,即首先是表示基本字符种类的值,然后是通过添加重音符号等来修改它的值,所以为了完全通用,你可以即使使用32位wchar_t
,也不要依赖字符作为单个值。
答案 2 :(得分:4)
编辑:要在switch语句中使用宏,需要对原始解决方案进行两次更改。首先,每个角色必须符合整体类型;确保这一点的最佳方法是使用wchar_t
的宽字符。其次,宏必须是字符文字而不是字符串文字。 E.G。
#define E_GRAVE L'\u00E8'
wchar_t someChar = ...;
switch(someChar)
{
case E_GRAVE :
x = 1;
break;
...
}
<小时/> 一种完全可移植的方法是为重音字符定义宏并依赖字符串连接。
// è (U+00E8) in UTF-8 encoding
#define E_GRAVE "\xC3\xA8"
cout << "Resum" E_GRAVE << endl;
这当然假设您正在使用UTF-8。您可以通过这种方式支持任何字符集。以下是使用UTF-16在Windows上执行此操作的方法:
#define E_GRAVE L"\u00E8"
wchar_t * resume = L"Resum" E_GRAVE;