the*_*rce 29 c++ winapi ucs2 utf-8 utf-16
今天我醒来后觉得我的代码和我用过的每个图书馆都出现了严重问题,我认为我是对的......(或者请指出我的推理错误的地方)
让我们回到过去十年或者两年,一切都在世界上很好.我跟我的邻居说话,他讲的是同一种语言:只是简单的英语.对我来说,我的邻居和Windows似乎很明显将我们的字符串存储在8位chars中,因为我们使用的所有字符都可以存储在2 ^ 8 = 256种可用组合中.
然后奇迹般的互联网出现了,并允许我与欧洲的一些朋友(他们没有时间学习英语)交谈.这很难用我们的char格式,使用的字符数量很容易超过256,所以在我们完全简单的视觉中我们决定使用16位wchar_ts.称为UCS-2 unicode的东西.它有2 ^ 16 = 65.536种可用组合,对于世界上的每种语言都必须足够!相信我们的正确性,我们甚至还添加了16位的Windows API的W功能,如MessageBoxW和CreateWindowW.我们说服了每个程序员我们的宗教,并且不鼓励使用邪恶的8位对应物(MessageBoxA和CreateWindowA)并通过在我们的构建中定义来MessageBox自动映射调用.因此我们也应该使用函数而不是旧函数(例如,现在应该使用,或者使用自动映射).MessageBoxW_UNICODEwcsstrstrlenwcslen_tcslen
然后事情变得糟糕,事实证明世界上还有其他人使用甚至比我们更怪异的字形(没有冒犯):日本人,中国人等等.它变坏了,因为例如中国人有超过70,000个不同的字符.发生了很多咒骂,给我们留下了一种新型的unicode:UTF-16.它还使用16位数据类型,但某些字符需要两个16位值(称为代理对).这意味着我们不能在这些16位字符串上使用索引(例如,theString [4]可能不会返回第5个字符).为了修补Windows API,决定所有W函数现在应该支持UTF-16格式,这是一个简单的决定,因为所有旧的UCS-2字符串也是有效的UTF-16字符串.但是,因为我们是勇敢的程序员,所以我们现在使用这些wcs功能.遗憾的是,这些功能不具有代理意识,仍然符合UCS-2格式......
与此同时,在一个黑暗的阁楼里,开发了另一种更紧凑的unicode形式:UTF-8.使用8位数据类型,大多数西方语言可以存储在一个8位值中,就像过去一样.当存储更奇特的字形时,使用多个8位值,对于大多数欧洲语言2就足够了.但是,它可能会扩展其中4个值,实质上是创建32位存储类型.就像它的胖兄弟UTF-16一样,我们不能在这些字符串上使用索引.由于它更紧凑的格式,UTF-8现在在互联网上的各个地方广泛使用,因为它节省了带宽.
很好,你是通过我冗长的写作来实现的:)现在我有一些问题/兴趣点:
好的,我对使用UTF-8进行存储非常满意.当我读取一个文件(来自磁盘或HTTP响应)时,我检测到UTF-8签名"\xEF\xBB\xBF"并将内容放在MultiByteToWideChar我的UTF-16字符串中.我可以使用WAPI函数,没问题.但是现在我想修改字符串,替换一些字符等.好的旧wcs函数不再好了,哪些核心字符串函数是UTF-16识别的?还是有一些出色的图书馆,我不知道吗?编辑:似乎ICU是一个非常好的解决方案.我还发现这些wcs函数并不是完全无用的,你可以用来wcsstr搜索,它基本上只是比较wchar_ts.唯一的问题是字符串的长度.
当我们被迫使用16位缺陷W函数时,你是否感觉到了一个丑陋的错误.难道问题不应该在更早的阶段得到认可,并且让所有原始API函数都采用UTF-8字符串并包含适当的字符串操作例程吗?或者这已经是可能的,我可怕的错了吗?编辑:也许这是一个愚蠢的问题,后见之明确实很精彩,现在没有人放下任何人;)
为了快速索引字符,我们应该以32位值存储字符串.这是常见的吗?(我可以听到你的想法:然后我们遇到了一种需要更多组合的外星语言,并且乐趣又重新开始...)这种方法的缺点似乎是我们应该每次将字符串转换回UTF-16我们进行Windows API调用.编辑:引用Alf P. Steinbach 每个指数一个角色是一个绝望的梦想,我现在看到了.我完全错过的一件事是变音符号.我也认为在OS的本机编码中处理是一件好事(对于Windows UTF-16).虽然UTF-8本来是一个更好的选择,但我们现在仍然坚持使用UTF-16,在代码和API之间来回转换没有任何意义.如下所示,我将通过指针而不是字符计数来跟踪字符串中的部分.
虽然这个冗长的问题,我认为你应该为自己喝上一杯好茶,在你回答之前去拿一个;)
编辑:我接受我的问题已被关闭的事实,这将更适合博客文章,但我再次不写博客.我认为这个字符编码的东西是必不可少的,应该是简单的hello world示例之后的任何编程书中的下一个主题!在这里发帖引起了许多专家的注意,那些人没有阅读任何随机博客,我非常重视他们的意见.所以感谢大家的贡献.
根据强烈的偏好,您应该在读取数据时从UTF-*转换为UCS-4.您的所有处理都应在UCS-4上完成,然后(如有必要)在输出期间转换回UTF-*.
但这仍然无法解决所有问题.有一组"组合变音"标记,这意味着即使使用UCS-4,string[N]也不一定对应于字符串的第 N 个字符.有规范形式的转换试图帮助解决这个问题,但是它们并不总能完成这项工作,所以如果它真的很关键(对于你的应用程序),你只需要遍历字符串,将它分成每个单元.表示一个完整的字符(基本字符+和组合变音符号),并将每个字符视为一个单元.
我对此事的看法:
对于外部接口(文件,命令行参数,环境变量,stdin/out),使用UTF-8,因为这是一个字节流,整个C和C++语言是通过字节流与环境接口设计的.在大多数敏感的文件系统上,文件名也是(以null结尾的)字节字符串.
对于简单的parroting,你可以在内部使用UTF-8,使用char*等,以及普通的""字符串文字或新的u8""UTF-8文字.
对于文本操作,在内部将字符串转换为UTC-4/UTF-32并将其视为数组char32_t.这是你能说出字符串的唯一理智方式.
ICU - Unicode的国际组件.为了正确的单词分解和显示,Windows包括Uniscribe和非Windows使用FreeType(如果我错了,请纠正我).
是的,我愿意.但据我所知,当他们做出这个决定时,utf-32并不存在,他们认为65536个代码点"对每个人来说都足够了".
不,这不对.除了内存使用量增加四倍外,问题还比你想象的要糟糕得多.你不能只是"修改一个字符串"和"替换一些字符":即使使用32位值,因为一个unicode字符不一定意味着一个书面字母或一个字形,你可以删除或替换其他东西,并希望什么也不希望休息.要正确使用文本,你必须使用像ICU这样的东西,所以使用utf-8和utf-32之间没有太大区别.