问题描述
我正在从attoparsec文档中查看this example:
simpleComment = string "<!--" *> manyTill anyChar (string "-->")
这将构建[Char]
而不是ByteString
切片。带有大量评论不是很好,对吧?
另一种选择,takeWhile:
takeWhile :: (Word8 -> Bool) -> Parser ByteString
不能接受解析器(即不能匹配ByteString
,只能匹配Word8
)。
是否有一种方法可以使用attoparsec解析ByteString
的块,而无需在过程中构建[Char]
?
解决方法
您可以使用scan
:
scan :: s -> (s -> Word8 -> Maybe s) -> Parser ByteString
状态扫描器。谓词使用并转换状态参数,然后将每个转换后的状态传递给输入的每个字节上谓词的连续调用,直到返回Nothing或输入结束。
它看起来像这样:
transitions :: [((Int,Char),Int)]
transitions = [((0,'-'),1),((1,2),((2,'>'),3)]
dfa :: Int -> Word8 -> Maybe Int
dfa 3 w = Nothing
dfa s w = lookup (s,toEnum (fromEnum w)) transitions <|> Just 0
然后使用scan 0 dfa
提取直到最后一个"-->"
为止的字节。我在这里使用的状态告诉我们到目前为止已经看到了"-->"
个字符。看到所有内容后,我们会通知scan
该停止了。这仅仅是为了说明这个想法。为了提高效率,您可能想要使用比关联列表更有效的数据结构,将*Enum
调用移至查找表,甚至考虑直接编写函数。