程序究竟如何在内部将所有内容转换为UTF-8?

时间:2010-05-07 11:35:43

标签: c internationalization

  • 是否使用setlocale()?
  • 当处于UTF-8语言环境时,它是否假设所有输入字符串都是utf-8?
  • 我明白unicode是什么以及它与utf-8有什么关系,但是如何在内部用它们的所有字符串“转换为它”?

它如何将所有输入字符串转换为UTF-8?它是否使用C库函数?

当前工作区域设置是否必须是UTF-8语言环境?

更新:如果您的答案中有特定的技术细节,那就更好了,因为这更符合我的要求。我已经理解了在内部使用UTF-8的原因以及为什么它使处理多个语言环境变得更加简单。

更新:提到简单地使用iconv和/或ICU的答案,然而,strcmp()和所有其他例程如何知道将它们作为UTF-8进行比较呢? setlocale()必须运行吗?或者没关系?

5 个答案:

答案 0 :(得分:5)

要说明从哪里开始有点难,因为有很多假设在起作用。

在C中我们知道并喜欢它,有一个'char'数据类型。在所有常用的实现中,该数据类型保存一个8位字节。

在语言中,与您使用的任何库函数相反,这些东西只是二进制补码整数。它们没有任何“字符”语义。

一旦你开始用标准库中的'str'或'is'来调用函数(例如strcmp,isalnum),你就会处理字符语义。

C程序需要在Unicode发明之前应对由字符语义构成的巨大混乱。各种组织发明了大量的编码标准。有些是每个字节一个字符。有些是每个字节多个字符。在某些情况下,问if (charvalue == 'a')总是安全的。在其他情况下,由于多字节序列,可能会得到错误的答案。

在几乎所有现代环境中,标准库的语义都由语言环境设置决定。

UTF-8在哪里?很久以前,Unicode联盟的成立是为了试图摆脱所有这些混乱的秩序。 Unicode为许多很多字符定义了一个字符值(在32位字符空间中)。目的是涵盖实际使用的所有特征。

如果您希望您的代码使用英语,阿拉伯语,中文和Sumerian Cuneiform,您需要Unicode字符语义,而不是编写躲避和编织不同字符编码的代码。

从概念上讲,最简单的方法是使用32位字符(UTF-32),因此每个逻辑字符都有一个项目。大多数人认为这是不切实际的。请注意,在现代版本的gcc中,数据类型wchar_t是32位字符---但Microsoft Visual Studio不同意,将数据类型定义为16位值(UTF-16或UCS-2,具体取决于你的观点)。

大多数非Windows C程序在8位字符上投入太多而无法更改。因此,Unicode标准包括UTF-8,Unicode文本的表示形式为8位字节序列。在UTF-8中,每个逻辑字符的长度在1到4个字节之间。基本的ISO-646('ascii')字符'自己播放',因此对简单字符的简单操作按预期工作。

如果您的环境包含UTF-8的语言环境,那么您可以将语言环境设置为UTF-8语言环境,并且所有标准的lib函数都可以正常工作。如果您的环境不包含UTF-8的区域设置,您将需要一个附加组件,如ICU或ICONV。

到目前为止,整个讨论一直停留在内存中的变量数据中。你还必须处理阅读和写作。如果您调用open(2)或Windows道德等效项,您将从文件中获取原始字节。如果那些不是UTF-8,如果你想使用UTF-8,你必须转换它们。

如果你打电话给fopen(3),那么标准库可能会帮你一个忙,并在它对文件的默认编码的想法和你想要的内存想法之间进行转换。例如,如果你需要在希腊语语言环境中运行程序并在Big5中读取中文文件,你需要小心你传递给fopen的选项,或者你可能想要躲开它。而且你需要ICONV或ICU来转换UTF-8和从UTF-8转换。

您的问题提及'输入字符串'。这可能是一些事情。在UTF-8语言环境中,argv将为UTF-8。文件描述符0将是UTF-8。如果shell未以UTF-8语言环境运行,并且您将setlocale调用为UTF-8语言环境,则不一定会在argv中获得UTF-8中的值。如果将文件的内容连接到文件描述符,您将获得文件中的任何内容,无论它采用何种编码方式。

答案 1 :(得分:2)

呃......我想你问的问题是libiconvICU,但是......它们只是用于转换字符集的库......

修改

您不能使用标准C字符串处理函数,因为您不处理标准C字符串。支持UTF-8的版本可在glibICU等库中使用。

答案 2 :(得分:1)

字符串实际上是一个抽象概念。但是在计算机内部,任何字符串都将具有使用特定字符编码的具体表示形式。

所以“在内部将所有内容转换为UTF-8”意味着应用程序在内部对所有字符串使用UTF-8,编写所有逻辑以在UTF-8字符串上运行,并从字符串使用的任何编码转换每个外部输入到UTF-8。它可能允许也可能不允许您选择用于输出的编码。

这是编写能够处理不同编码文本的应用程序的最明智的方法,至少如果内部逻辑可以在UTF-8上有效工作(即不需要随机访问)。

答案 3 :(得分:1)

ICU内部使用utf-16(这是一种很好的内部工作格式),但有比较utf-8的便利例程。您可以告诉它要用于比较的区域设置,或者如果指定区域设置“root”,它可以使用未修改的UCA

答案 4 :(得分:0)

如果你想比较C中的两个字符串,它们都必须使用相同的编码。 strcmp()只是一个memcmp()(或逐字节比较),它在0的值处停止。在C的strcmp中没有任何转换。如果你必须处理不同的编码(CP850,UTF-8,Ansi,Windows,Mac),你必须非常仔细地比较,否则你将苹果与梨进行比较。

上面提到的库有一个不同的strcmp()实现,它知道并处理编码,你必须知道并自己提供编码。

如果您处理XML,您可以使用libxml,它以正确的(内部)表示形式为您编码,具体取决于通过xml-header的给定编码。

编码/字符表是C中最糟糕的概念之一,可以追溯到古老的日子,其中7位长的字符字节和计算机世界只在美国发生。 (所以没有变音符号,口音,欧元符号等)