我的程序如何从ASCII切换到Unicode?

时间:2010-08-31 20:53:30

标签: c++ unicode

我想用C ++编写一个适用于Unix和Windows的程序。该程序应该能够同时使用:Unicode和非Unicode环境。其行为应仅取决于环境设置。

我想要的一个很好的功能是操作从目录中读取的文件名。这些可以是unicode ......或者不是。

实现这一目标的最简单方法是什么?

6 个答案:

答案 0 :(得分:9)

  

我想用C ++编写一个程序   应该适用于Unix和Windows。

首先,确保您了解Unix如何支持Unicode以及Windows如何支持Unicode之间的区别。

在Unicode之前的日子里,两个平台的相似之处在于每个语言环境都有自己的首选字符编码。字符串是char的数组。一个char =一个字符,除了少数使用双字节编码的东亚语言环境(由于非自同步而难以处理)。

但他们以两种不同的方式接近Unicode。

Windows NT在早期使用Unicode时,Unicode的目标是固定宽度的16位字符编码。 Microsoft使用16位字符(wchar_t)而不是8位字符编写了一个全新版本的Windows API。为了向后兼容,他们保留旧的“ANSI”API并定义了大量的宏,因此您可以调用“ANSI”或“Unicode”版本,具体取决于是否定义了_UNICODE

在Unix世界(特别是贝尔实验室的Plan 9)中,开发人员认为扩展Unix现有的东亚多字节字符支持以处理3字节字符会更容易,并创建现在称为UTF-的编码8。近年来,类Unix系统一直将UTF-8作为大多数语言环境的默认编码。

Windows理论上可以扩展其ANSI支持以包括UTF-8,但是they still haven't,因为关于字符最大大小的硬编码假设。因此,在Windows上,您会遇到不支持UTF-8的OS API和不支持UTF-8的C ++运行时库。

这样做的结果是:

  • UTF-8是在Unix上使用的最简单的编码。
  • UTF-16是在Windows上使用的最简单的编码。

这为跨平台代码创造了与听起来一样多的复杂性。如果您只是选择一个Unicode编码并坚持下去,就会更容易。

应该是哪种编码?

请参阅UTF-8 or UTF-16 or UTF-32 or UCS-2

总结:

  • UTF-8允许您保留8位代码单元的假设。
  • UTF-32可让您保留固定宽度字符的假设。
  • UTF-16 sucks,但由于Windows和Java,它仍然存在。

wchar_t的

是标准C ++“宽字符”类型。但它的编码并不是标准化的:它在Windows上是UTF-16,在Unix上是UTF-32。除了那些使用语言环境依赖 wchar_t编码作为东亚编程遗产的平台之外。

如果要使用UTF-32,请使用uint32_t或等效的typedef来存储字符。如果已定义wchar_t__STDC_ISO_10646__,则使用uint32_t

新的C ++标准将有char16_tchar32_t,这有望消除对如何表示UTF-16和UTF-32的困惑。

TCHAR

是定义wchar_t_UNICODE(假设为UTF-16)的Windows typedef,否则为char(假设为“ANSI”)。它旨在处理上面提到的重载Windows API。

my opinion中,TCHAR很糟糕。它结合了依赖于平台的char的缺点和依赖于平台的wchar_t的缺点。避免它。

最重要的考虑因素

字符编码是关于信息交换的。这就是“II”代表ASCII的含义。你的程序不存在于真空中。您必须读取和写入文件,这些文件更可能以UTF-8编码而不是UTF-16编码。

另一方面,您可能正在使用使用UTF-16(或更少见的UTF-32)字符的库。在Windows上尤其如此。

我的建议是使用最小化转换量的编码格式。

  

这个程序应该可以使用   两者:Unicode和非Unicode   环境

最好让你的程序在内部完全使用Unicode,并且只处理遗留编码以读取遗留数据(或编写遗留数据,但如果明确要求则仅 。)

答案 1 :(得分:2)

您必须决定如何在内部代表文字 无论你选择什么,这都应该是不变的。

然后,无论何时读取任何输入,您都必须从输入格式转码为内部格式。然后从内部格式到输出格式的出路。如果您碰巧在内部和外部使用相同的格式,则会成为身份操作。

UTF-8非常适合存储和传输,因为它压缩得很好 但我不喜欢它作为内部表示,因为它具有可变长度。

UTF-16:应该是全人类的救世主 但很快就被UTF-32

所取代

UTF-32:修正了。因此非常适合内部表征和操纵 易于转换为UTF-8或从UTF-8转换 非常笨重(每个字符需要4个字节)。

大多数操作系统已经转换为UTF字符串表示形式或正在朝这个方向发展。因此,在ISO-8859内部使用onld obsolte格式只是意味着调用操作系统将导致额外的工作,因为字符串转换为/从UTF转换。结果这似乎是浪费时间(对我而言)。

答案 2 :(得分:1)

您必须决定使用哪种Unicode编码,例如UTF-8,ISO-8859-1等 那么你应该在你的C ++中考虑所有的字符串操作。例如。看看w_char和wstring。 在非Unicode环境中,我假设您的意思是输入变量只是ascii?

答案 3 :(得分:1)

“”(“空字符串”)的区域设置标识符指定特定于实现的默认区域设置。因此,如果将全局语言环境设置为std::locale(""),那么理论上,您将获得基于环境的语言环境设置初始化的默认语言环境。这与标准c ++给你的帮助差不多。

这在Windows上有一些主要限制,其中MSVC不会使用UTF-8编码提供任何std :: locale。并且Mac OS X不提供除文化中立的“C”语言环境之外的任何std :: locale。

在实践中,在应用程序内部的任何地方标准化UTF-8编码的std :: string是很常见的。然后,在需要与操作系统交互的特定情况下,根据需要进行代码转换。例如,您将使用以UTF-8编码的const char *在unix上定义文件名,但使用UTF-16编码的wchar *在Windows上定义文件名。

UTF-8是一种广泛推荐的内部字符集,适用于可移植的应用程序。 UTF-16具有与UTF-8相同的可变宽度编码问题,并且为许多语言使用更多空间。此外,UTF-16增加了字节顺序问题,并且对unix的支持相对较少。 UTF-32是最简单的编码,但它也使用最多的空间,并且在Windows上没有本机支持。

答案 4 :(得分:1)

就个人而言,我会走另一条路。

无论您选择何种格式,它都应该适应Unicode,这是给定的。但是,您当然不必限制使用现有编码。

特定的编码意味着可以轻松进行通信,但是由于Unix默认为UTF-8,Windows默认为UTF-16,因此无法进行通用编码。因此,我建议您使用自己的内部表示,并根据您定位的操作系统应用合适的转换。这是因为你需要的功能的通用接口和每个OS /编码的实现。

另请注意,无论您使用何种平台,您都应该能够动态更改编码/解码(例如,您可能会要求在Unix上使用UTF-32作为特定文件),另一个原因是使用给定的编码。

总结一下:

  • ICU很棒
  • 如果你自己实现它并希望有点“标准”使用UTF-32(每点4个字节)
  • 如果内存不足,21位(<3字节)足以编码所有现有点

转换可能看似“计算机密集型”,但是:

  • 你可以顺其自然地做到这一点
  • 它比I / O快得多

我的2 cts,正如他们所说:)

答案 5 :(得分:0)

我见过的最好方法是根据条件编译定义typedef和很少的宏。例如:

#ifdef UNICODE
#define mychar wchar_t
#define s(a) L ## a
typedef std::wstring mystringa;
#else
#define mychar char
#define s(a) a
typedef std::string mystringa;
#endif
typedef std::basic_string<mychar> mystringb;

等等。然后,您可以将字符串用作s("foo")mystringa(s("foo"));。我已经展示了两种创建字符串类型的方法。要么应该工作。