有没有办法在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
(这太好了!)但是我仍然需要能够在其他代码中获取字符词法分析程序。
答案 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")