我的平台是Mac和C++ 11(或更高版本).我是一名C++初学者,正在处理一个处理中文和英文的个人项目.UTF-8是此项目的首选编码.
我在Stack Overflow上阅读了一些帖子,其中许多人建议std::string在处理UTF-8时使用,并避免wchar_t因为char8_tUTF-8现在没有.
然而,他们没有谈论如何正确地与像函数处理str[i],std::string::size(),std::string::find_first_of()或者std::regex因为这些功能通常面临UTF-8时,返回意外的结果.
我应该继续std::string或切换到std::wstring?如果我应该std::string坚持下去,那么处理上述问题的最佳做法是什么?
Mat*_* M. 82
Unicode是一个庞大而复杂的主题.我不想在那里涉及太深,但是需要一个快速的词汇表:
这是Unicode的基础.Code Point和Grapheme Cluster之间的区别可能大部分被掩盖,因为对于大多数现代语言,每个"字符"都映射到一个代码点(常用字母+变音符组合有专用的重音形式).不过,如果你冒险使用表情符号,旗帜等......那么你可能不得不注意区别.
然后,必须编码一系列Unicode代码点; 常见的编码是UTF-8,UTF-16和UTF-32,后两种以Little-Endian和Big-Endian形式存在,共有5种常见编码.
在UTF-X中,X是代码单元的位大小,每个代码点表示为一个或多个代码单元,具体取决于其大小:
std::string和std::wstring.std::wstring如果你关心可移植性,请不要使用(wchar_t在Windows上只有16位); std::u32string改为使用(又名std::basic_string<char32_t>).std::string或std::wstring)独立于磁盘表示(UTF-8,UTF-16或UTF-32),因此请准备好在边界处进行转换(读取和写入).wchar_t确保代码单元代表完整的代码点,但它仍然不代表完整的Grapheme集群.如果你只阅读和撰写串,你应该没有与少的问题std::string或std::wstring.
当您开始切片和切块时,麻烦就开始了,那么您必须注意(1)代码点边界(UTF-8或UTF-16)和(2)Grapheme Clusters边界.前者可以自己轻松处理,后者需要使用Unicode感知库.
std::string还是std::u32string?如果性能是一个问题,std::string由于其较小的内存占用,它可能会表现更好; 虽然大量使用中国人可能会改变这笔交易.一如既往,简介.
如果Grapheme Clusters不是问题,则std::u32string具有简化事物的优点:1代码单元 - > 1代码点意味着您不会意外地分割代码点,并且所有功能都是std::basic_string开箱即用的.
如果您与软件接口std::string或char*/ 接口char const*,则坚持std::string避免来回转换.否则这将是一种痛苦.
std::string.UTF-8实际上效果很好std::string.
大多数操作都是开箱即用的,因为UTF-8编码是自同步的,并且与ASCII向后兼容.
由于代码点的编码方式,寻找代码点不会意外地匹配另一个代码点的中间:
str.find('\n') 作品,str.find("...")作品由字节匹配字节1,str.find_first_of("\r\n")作品如果搜索ASCII字符.同样,regex应该开箱即用.由于一系列字符("haha")只是一个字节序列("?"),基本的搜索模式应该是开箱即用的.
但是要警惕字符类(例如[:alphanum:]),因为它取决于正则表达式的风格和实现,它可能与Unicode字符匹配,也可能不匹配.
同样,要小心将转发器应用于非ASCII"字符","??"可能只考虑最后一个字节是可选的; 在这种情况下,使用括号清楚地描述重复的字节序列:"(?)?".
1 查找的关键概念是规范化和整理; 这会影响所有比较操作.std::string将始终逐字节地比较(并因此排序),而不考虑特定于语言或用法的比较规则.如果需要处理完全规范化/归类,则需要一个完整的Unicode库,例如ICU.
双方std::string 并std::wstring必须使用UTF编码来表示Unicode.特别std::string是在macOS上,是UTF-8(8位代码单元),std::wstring 是UTF-32(32位代码单元); 请注意,大小wchar_t取决于平台.
对于两者,size跟踪代码单元的数量而不是代码点的数量或字形集群.(代码点是一个名为Unicode的实体,其中一个或多个形成一个字形集群.字形集群是用户与之交互的可见字符,如字母或表情符号.)
虽然我不熟悉中国的Unicode表示,这是非常可能的,当你使用UTF-32的编码单元的数量通常是非常接近字形集群的数量.然而,显然,这需要使用多达4倍的内存.
最准确的解决方案是使用Unicode库(如ICU)来计算您所追求的Unicode属性.
最后,人类语言中不使用组合字符的UTF字符串通常与find/ 相当不错regex.我不确定中文,但英文就是其中之一.
std::string和朋友编码不可知.之间唯一的区别std::wstring和std::string是std::wstring使用wchar_t的单个元素,没有char.对于大多数编译器,后者是8位.前者应该足够大以容纳任何unicode字符,但实际上在某些系统上它不是(微软的编译器,例如,使用16位类型).你不能存储UTF-8 std::wstring; 这不是它的设计目标.它的设计相当于UTF-32 - 一个字符串,其中每个元素都是一个Unicode代码点.
如果要通过Unicode代码点或组合的unicode字形(或其他东西)索引UTF-8字符串,请计算Unicode代码点或其他一些unicode对象中UTF-8字符串的长度,或者通过Unicode代码点查找,你是需要使用标准库以外的东西.ICU是该领域的图书馆之一; 可能还有其他人.
值得注意的是,如果您正在搜索ASCII字符,则可以将UTF-8字节流视为逐字节处理.每个ASCII字符在UTF-8中编码与在ASCII中编码相同,并且UTF-8中的每个多字节单元保证不包括ASCII范围内的任何字节.
小智 5
考虑升级到 C++20,std::u8string这是截至 2019 年我们拥有的最好的东西来保存 UTF-8。没有标准的库工具来访问单个代码点或字素簇,但至少你的类型足够强大,至少可以说它是真正的 UTF-8。
| 归档时间: |
|
| 查看次数: |
15675 次 |
| 最近记录: |