我正在尝试解析一个字符串,比如
AA{A}{END}}
给定地图:fromList [("{",43),("}",44),("{END}",255),("A",65)]
,
以便所需的输出为:[65,65,43,65,44,255,44]
看起来在直接Haskell中搜索地图中最长的前缀,但是如何用Parsec解析它?它类似于this question,但在这里我应该返回Word8
值而不是'choice'解析的字符串。
答案 0 :(得分:3)
首先需要编写一个解析器,将(Word8, Int)
元组作为输入,并返回Parser Word8
值。
keyValParser :: (String, Word8) -> Parser Word8
keyValParser (s,v) = try (string s) >> return v
上面的解析器对try
解析器使用string
因为Parsec有一个讨厌的习惯,即使在失败时也会消耗匹配的字符。如果try (string s)
部分成功,则会从元组返回Word8
值。
现在,您可以根据keyValParser
映射输入列表,以构建您正在寻找的解析器:
parser :: [(String, Word8)] -> Parser [Word8]
parser = many . choice . map keyValParser
在GHCi中使用parseTest
运行此解析器会产生:
> let lookup = [("{",43),("}",44),("{END}",255),("A",65)]
> parseTest (parser lookup) "AA{A}{END}}"
[65,65,43,65,44,43]
但是等等!那不太对劲。现在的问题是choice
在第一个匹配的解析器处停止,字符串{END}
首先匹配{
,因此返回43
。您可以先使用lookup
sortBy (flip $ comparing (length . fst))
值来解决此问题
parser :: [(String, Word8)] -> Parser [Word8]
parser = many . choice . map keyValParser . sortBy (flip $ comparing (length . fst))
现在你得到了正确的结果:
> let lookup = [("{",43),("}",44),("{END}",255),("A",65)]
> parseTest (parser lookup) "AA{A}{END}}"
[65,65,43,65,44,255,44]