haskell:将带有unicode字符的字符串转换为64位的块

时间:2016-03-22 16:24:47

标签: haskell unicode

我希望将String转换为64位的块。我不确定ByteString是否是正确使用的数据类型,但经过一些测试后,我意识到我无法将String转换为ByteString并返回:

import qualified Data.ByteString.Lazy.Char8 as B
main = putStrLn $ B.unpack $ B.pack "☂♞☯"

结果:

^/

不应该打印☂♞☯

我的第二次尝试是将String拆分为Int个列表,每个Int代表一个字符:

main = putStrLn $ show $ map fromEnum "☂♞☯"

结果:

[9730,9822,9775]

现在我该如何将此列表转换为64位块列表?重要的是,我之后能够将64位块转换回String,而不会丢失任何信息。

2 个答案:

答案 0 :(得分:3)

The ByteString.Char8 documentation says(强调我的):

  

使用ByteStrings操作操纵Char。所有字符将截断为8位。可以预期这些函数将以与Data.ByteString中的Word8等价物相同的速度运行。

IOW,这仅适用于您对纯ASCII字符串的期望。好吧,模块名称中的Char8已经建议了,不是吗?所以,不,它不应该打印☂♞☯

你的第二种方法更有意义。为了使其可靠,您不应使用Int而是使用Word64;您可以使用fromIntegral . fromEnum而不是后者转换为此类型。

尝试直接从这些单词构建ByteString并不可取,因为类似数组的东西的纯函数级联效果不佳。但是Binary.Builder模块有一个有效的monoid用于此目的。 monoid可以直接映射到列表上:

> toLazyByteString $ foldMap (putWord64le . fromIntegral . fromEnum) "☂♞☯"
"\STX&\NUL\NUL\NUL\NUL\NUL\NUL^&\NUL\NUL\NUL\NUL\NUL\NUL/&\NUL\NUL\NUL\NUL\NUL\NUL"

因此,这些是您要求的实际64位块。 Basicall UTF-64,当然空间效率很高。

根据你想要做的事情,一个更好的选择可能只是encode字符串:

Prelude Data.Binary> encode "☂♞☯"
"\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ETX\226\152\130\226\153\158\226\152\175"

这实际上将字符串存储为UTF-8(加上存储在前八个字节中的 length 信息)。这可以很容易地撤消:

Prelude Data.Binary> putStrLn . decode $ encode "☂♞☯"
☂♞☯

答案 1 :(得分:2)

UTF-8

假设UTF-8,utf8-string包实现了所需的编码算法。下面的encode函数需要String并返回一个无符号字节数组。

module Main where

import Codec.Binary.UTF8.String as UTF8

main :: IO ()
main =
  print (UTF8.encode "☂♞☯")

输出:

λ> main
[226,152,130,226,153,158,226,152,175]

如您所见,UTF-8将您的Unicode字符串表示为九个不同的字节。您必须编写自己的代码将它们转换为64位的块。有很多不同的方法来分块!