问题 如何在C / C ++中处理unicode字符序列?


在C和C ++中处理unicode字符序列的更便携和干净的方法是什么?

而且,如何:

- 阅读unicode字符串

- 将unicode字符串转换为ASCII以保存一些字节(如果用户只输入ASCII)

- 打印unicode字符串

我也应该使用这个环境吗?我已经读过关于LC_CTYPE的例子,我应该关心它作为开发人员吗?


11703
2017-09-02 03:49


起源

相关 stackoverflow.com/questions/3613149/3614105#3614105 - dan04


答案:


什么是更便携和清洁   处理unicode字符的方法   C和C ++中的序列?

拥有程序中的所有字符串 UTF-8,UTF-16或UTF-32。如果由于某种原因需要使用非Unicode编码,请对输入和输出进行转换。

读取unicode字符串

您读取ASCII文件的方式相同。但是周围仍然有很多非Unicode数据,所以你要检查数据是否存在  Unicode格式。如果不是(或当你首选的内部编码是UTF-32时它是UTF-8),你需要转换它。

  • 通过验证可以可靠地检测UTF-8和UTF-32。
  • 可以通过BOM的存在来检测UTF-16。
  • 如果它不是UTF编码,则可能在ISO-8859-1或Windows-1252中。

将unicode字符串转换为ASCII   保存一些字节(如果只是用户   输入ASCII)

别。如果您的数据都是ASCII,那么UTF-8将占用完全相同的空间。如果不是,转换为ASCII时将丢失信息。如果你关心保存字节。

  • 选择最佳的UTF编码。对于字符U + 0000到U + 007F,UTF-8是最小的。对于字符U + 0800到U + FFFF,UTF-16是最小的。
  • 像gzip一样使用数据压缩。有一个专门为Unicode设计的SCSU编码,但我不知道它有多好。

打印unicode字符串

编写UTF-8与编写ASCII没有什么不同。

除了在Windows命令提示符下,因为它仍然使用旧的“OEM”代码页。在那里你可以使用 WriteConsoleW 使用UTF-16字符串。

我也应该使用这个环境吗?   我读过有关LC_CTYPE的例子,   我应该关心它作为开发人员吗?   ?

LC_CTYPE 从每种语言都有自己的字符编码的日子开始,这是一种保留 ctype.h 功能。今天, Unicode字符数据库 照顾好这一点。 Unicode的美妙之处在于它 中隔离 从区域设置处理的字符编码处理(除了 特殊的大写/小写规则 立陶宛语,土耳其语和阿塞拜疆语)。

但是每种语言仍然有自己的排序规则和数字格式规则,因此您仍然需要这些语言环境。您需要将区域设置的字符编码设置为UTF-8。


8
2017-09-02 04:34



优秀的概述,特别是因为它避免了任何编程语言特定的东西 - Jens Gustedt


在C和C ++中处理unicode字符序列的更便携和干净的方法是什么?

使用类似的库 ICU。如果你做不到,那就是绝对不可能 - 不能自己滚动。准备好了 困难时期虽然。另外,请查找 Unicode.org示例源代码的文档。

我也应该使用这个环境吗?

是。您可能需要使用 std::setlocale 功能也是如此。这将允许您设置与您想要的编码相对应的区域设置,例如如果您想使用英式英语作为语言而使用UTF-8作为编码 LC_CTYPE 到en_GB.UTF8

C ++ 03没有给你一种处理Unicode的方法。你最好的选择是使用 wchar_t 数据类型(以及扩展名 std::wstring)。但请注意,不同操作系统的大小和字符编码是不同的。例如。 Windows使用2个字节 wchar_t 和UTF-16编码,而GNU / Linux和Mac OSX使用4个字节和UTF-32。

C ++ 0x应该通过允许Unicode文字来修改这种情况 codecvt facets,C Unicode TR支持(读取 <uchar.h>)等等,但对大多数编译器来说,这是一个很长的路要走。 (这里有几个问题应该可以帮助你开始。)


3
2017-09-02 04:00



-1 std :: wstring!= 该 Unicode字符串; std :: string是完全的Unicode字符串,如std :: wstring! - Artyom
我没说过 std::wstring 是Unicode。 - dirkgently
我的观点是这样的: std::wstring 可用于UTF16(在Windows上)和UTF32(在Mac / Linux上)。 UTF8最大的问题是它是一个可变宽度编码,因此是一个 char 或者a wchar_t  可能 无法跨平台表示Unicode字符。 - dirkgently
UTF-16也是可变宽度编码。即使访问单个代码点也通常是无用的。因为它甚至不代表一个角色。因此,对于文本分析,您需要使用像ICU这样的强大库,对于基本用途,使用UTF-8的std :: string与宽字符串一样完美。 - Artyom
W.r.t UTF-8是的,要么有效。如果你注意到,我的答案的第一行是ICU。 - dirkgently


如果适合,您需要将Unicode读取,打印或转换为ASCII吗?只需使用UTF-8,所有这些对您来说绝对透明。

  • 阅读,写作没有区别
  • ASCII已经是UTF-8的子集

对于文本分析/处理,使用ICU,Boost.Locale甚至Qt,Glib等优秀的库,它们提供了非常好的文本分析/处理工具。


0
2017-09-02 03:53





在这之前写好了很好的答案,但是他们都没有提到我认为可能存在的问题,因为这个问题也有 C 标签。我的C知识已经过时,如果我错了,请纠正我。

请注意,大概是零终止的字符串,传统的C字符串函数和UTF-16编码的数据流可能是一个棘手的组合,因为在UTF-16中,许多西方字母数字字符将被编码为两个字节,其他字节全为零,因此读取字符数据系列 chars不是单字节字符集所用的。


0
2017-09-03 01:42



您可以使用带有UTF-16的0x0000终止字符串。 ICU(如上所述)非常广泛地支持这一点。正如您所指出的,您不能假设UTF-16适合8位字符。 - Steven R. Loomis