从`ByteString`获取`Char`

时间:2016-11-04 02:39:11

标签: haskell text utf-8 ghc bytestring

有没有办法在O(1)时间内在Char中获得第一个UTF-8 ByteString?我正在寻找像

这样的东西
headUtf8 :: ByteString -> Char
tailUtf8 :: ByteString -> ByteString

我还没有被限制使用严格或懒惰ByteString,但我更喜欢严格。对于懒惰的ByteString,我可以通过Text拼凑一些东西,但我不确定这是多么有效(特别是空间复杂度)。

import qualified Data.Text.Lazy as T
import Data.Text.Lazy.Encoding (decodeUtf8With, encodeUtf8)
import Data.Text.Encoding.Error (lenientDecode)

headUtf8 :: ByteString -> Char
headUtf8 = T.head . decodeUtf8With lenientDecode

tailUtf8 :: ByteString -> ByteString
tailUtf8 = encodeUtf8 . T.tail . decodeUtf8With lenientDecode

如果有人感兴趣,当使用Alex制作支持UTF-8字符 1 的词法分析器时会出现此问题。

1 我知道,因为Alex 3.0你只需要提供alexGetByte(这太好了!)但是我仍然需要能够在其他代码中获取字符词法分析程序。

2 个答案:

答案 0 :(得分:4)

你想要utf8-string包中的Data.Bytestring.UTF8模块。它包含具有以下签名的uncons函数:

uncons :: ByteString -> Maybe (Char, ByteString)

然后您可以定义:

headUtf8 :: ByteString -> Char
headUtf8 = fst . fromJust . uncons

tailUtf8 :: ByteString -> ByteString
tailUtf8 = snd . fromJust . uncons

答案 1 :(得分:0)

The longest UTF-8 encoding is 6 bytes,所以如果我们尝试1,2,...字节,它至少会在第6步完成,从而 O(1)

import Data.Text as Text
import Data.Text.Encoding as Text
import Data.ByteString as BS

splitUtf8 :: ByteString -> (Char, ByteString)
splitUtf8 bs = go 1
  where
    go n | BS.null slack = (Text.head t, bs')
         | otherwise = go (n + 1)
      where
        (bs1, bs') = BS.splitAt n bs
        Some t slack _ = Text.streamDecodeUtf8 bs1

例如,此处分割2 + 3字节ByteString

*SO_40414452> splitUtf8 $ BS.pack[197, 145, 226, 138, 162]
('\337',"\226\138\162")

这里是3 + 2字节的一个:

*SO_40414452> splitUtf8 $ BS.pack[226, 138, 162, 197, 145]
('\8866',"\197\145")