Cel*_*tas 14 c++ unicode portability
我希望我的程序尽可能便携.我在字符串中搜索重音字符,例如è.这可能是个问题吗?是否有类似于HTML实体的C++?
它将用于switch语句,例如:
switch(someChar) //someChar is of type char
{
case 'é' :
x = 1;
break;
case 'è' :
...
}
Run Code Online (Sandbox Code Playgroud)
bam*_*s53 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或十六角逃逸那样常用.
以下是在使用ISO-8859-1或cp1252编码的源文件中使用"é"时Clang显示的诊断:
warning: illegal character encoding in character literal [-Winvalid-source-encoding]
std::printf("%c\n",'<E9>');
^
Run Code Online (Sandbox Code Playgroud)
Clang仅将此作为警告发出,并将直接输出具有源字节值的char对象.这样做是为了向后兼容非UTF-8源代码.
如果你使用UTF-8编码的源,那么你得到这个:
error: character too large for enclosing character literal type
std::printf("%c\n",'<U+00E9>');
^
Run Code Online (Sandbox Code Playgroud)
Clang检测到UTF-8编码对应于Unicode代码点U + 00E9,并且此代码点超出了单个char可以容纳的范围,因此报告错误.(Clang也逃脱了非ascii字符,因为它确定它运行的控制台无法处理打印非ascii字符).
形式上,即使在标识符中,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中,a wchar_t只有16位,标准编码是UTF-16,其中所谓的基本多语言平面(原始的16位Unicode)之外的字符用两个称为代理对的值表示.更糟糕的是,即使使用UTF-32,Unicode也允许用两个或多个值表示重音字符,即首先是表示基本字符种类的值,然后是通过添加重音符号等来修改它的值,所以为了完全普遍,你可以即使使用32位,也不依赖于单个值的字符wchar_t.