【问题标题】:unicode:characters_to_list seems doesn't work for utf8 listunicode:characters_to_list 似乎不适用于 utf8 列表
【发布时间】:2013-10-13 05:51:26
【问题描述】:

我正在尝试使用Erlang library "unicode 将 UTF-8 字符串转换为 Unicode(代码点)列表。我的输入数据是一个字符串“АБВ”(俄罗斯字符串,正确的 Unicode 表示为 [1040,1041,1042]),以 UTF-8 编码。当我运行以下代码时:

1> unicode:characters_to_list(<<208,144,208,145,208,146>>,utf8).
[1040,1041,1042]

它返回正确的值,但如下:

2> unicode:characters_to_list([208,144,208,145,208,146],utf8).  
[208,144,208,145,208,146]

没有。为什么会发生?正如我在specification 中读到的,输入数据可以是二进制或字符列表,所以,就我而言,我做的一切都是正确的。

【问题讨论】:

    标签: unicode encoding utf-8 erlang


    【解决方案1】:

    函数的签名是unicode:characters_to_list(Data, InEncoding),它期望Data 是包含以InEncoding 编码编码的字符串的二进制文件,或者可能是InEncoding 编码的深度字符列表(代码点)和二进制文件。它返回 unicode 字符列表。 erlang 中的字符是整数。

    当您调用unicode:characters_to_list(&lt;&lt;208,144,208,145,208,146&gt;&gt;, utf8)unicode:characters_to_list([1040,1041,1042], utf8) 时,它会正确解码unicode 字符串(是的,只要Data 是整数列表,第二个就是noop)。但是当您调用unicode:characters_to_list([208,144,208,145,208,146], utf8) 时,erlang 认为您以utf8 编码传递了 6 个字符的列表,因为它已经是 unicode,所以输出将完全相同。

    erlang 中没有 byte 类型,但您假设 unicode:characters_to_list/2 将接受 list of bytes 并且行为正确。

    总结一下。在 erlang 中有两种常用的方式来表示字符串,它们是位串和字符列表。 unicode:characters_to_list(Data, InEncoding)InEncoding 编码中采用这些表示之一(或它们的组合)中的字符串Data,并将其转换为unicode代码点列表。

    如果您的示例中有[208,144,208,145,208,146] 列表,您可以使用erlang:list_to_binary/1 将其转换为二进制,然后将其传递给unicode:characters_to_list/2,即

    1> unicode:characters_to_list(list_to_binary([208,144,208,145,208,146]), utf8).
    [1040,1041,1042]
    

    unicode 模块仅支持 unicode 和 latin-1。因此,(因为函数需要 unicode 或 latin-1 的代码点)characters_to_list 在代码点的平面列表的情况下不需要对列表做任何事情。但是,列表可能很深 (unicode:characters_to_list([[1040],1041,&lt;&lt;1042/utf8&gt;&gt;]).)。这就是支持Data 参数的列表数据类型的原因。

    【讨论】:

    • 谢谢,这听起来很合理。但我有一个问题:) 如果在这种情况下它什么都不做,只是认为你传递了一个 unicode 字符列表,那么在函数 characters_to_list 中传递列表有什么意义?
    • @koluch 字符串可能采用其他编码(InEncoding 参数)。它仅适用于 unicode(及其子集)。它认为它是 unicode,因为您将 utf8 作为 InEncoding 传递(将 unicode 字符列表转换为 unicode 字符列表)。我试图在回答中强调这一点,但我想我失败了。英语不够好:-(
    • 不,这与你的 Endlish 无关,我确实理解你:) 但是,DataInEncoding 的任何可能组合都会返回相同的结果!例如,如果您将其称为("abc", latin1),它将返回相同的内容(因为latin1 中的字符串是正确的 unicode 字符串),而对于另一个 utf 编码,它会返回相同的内容(例如,unicode:characters_to_list(binary_to_list(&lt;&lt;"abc"/utf32&gt;&gt;),utf32))。不是,请您举一个DataInEncoding 的组合示例,当characters_to_list 将返回除Data 之外的任何其他内容时
    • 如果您进一步检查函数定义,您会发现Data 是“可能很深的整数和二进制列表”,输出是“表示 Unicode 字符的整数列表” .它有一种内置的超级“扁平化”,其中二进制文件被编码,列表元素是 unicode 值。有一个 characters_to_binary 以类似的方式工作,但输出是一个编码二进制文件。
    • 是的,但是这些函数不仅采用列表或二进制,还采用组合
    【解决方案2】:

    &lt;&lt;208,144,208,145,208,146&gt;&gt; 是一个 UTF-8 二进制文件。

    [208,144,208,145,208,146] 是字节列表(不是代码点)。

    [1040,1041,1042] 是代码点列表。

    您正在传递一个字节列表,但该函数需要一个字符列表或二进制文件。

    【讨论】:

    • 字节列表和字符列表有什么区别? erlang 中没有“字节”类型,char 只是区间 0..16#10ffff (erlang.org/doc/reference_manual/typespec.html) 中的整数。所以,对我来说,[208,144,208,145,208,146] 是整数列表(换句话说,是字符列表)
    • @koluch 在某种意义上没有区别,Erlang 没有字符数据类型。这完全取决于它们的解释方式,“byte”是 0..255,而“char”是 0..16#10ffff,一个完整的 unicode 代码点。
    • 同一个整数作为字节和作为字符有不同的含义。
    • 这是一个示例:代码点 208 是“LATIN CAPITAL LETTER ETH”(这不是您想要的)。但在您的情况下,208 是代码点 1040“西里尔大写字母 A”的一部分,它可以在 UTF-8 中编码为 >。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2023-04-06
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多