我正在使用Text.ParserCombinators.Parsec和Text.XHtml来解析这样的输入:
- First type A\n -- First type B\n - Second type A\n -- First type B\n --Second type B\n
我的输出应该是:
<h1>1 First type A\n</h1>
<h2>1.1 First type B\n</h2>
<h1>2 Second type A\n</h2>
<h2>2.1 First type B\n</h2>
<h2>2.2 Second type B\n</h2>
我已经来到这一部分,但我无法进一步:
title1= do{
;(count 1 (char '-'))
;s <- many1 anyChar newline
;return (h1 << s)
}
title2= do{
;(count 2 (char '--'))
;s <- many1 anyChar newline
;return (h1 << s)
}
text=do {
;many (choice [try(title1),try(title2)])
}
main :: IO ()
main = do t putStr "Error: " >> print err
Right x -> putStrLn $ prettyHtml x
这没关系,但不包括编号。
有什么想法吗?
谢谢!
答案 0 :(得分:6)
您可能希望使用包含当前节号的状态的GenParser作为相反顺序的列表,因此1.2.3节将表示为[3,2,1],并且可能是要避免的列表长度反复计算它。像
这样的东西data SectionState = SectionState {nums :: [Int], depth :: Int}
然后使您的解析器操作返回类型为“GenParser Char SectionState a”。您可以使用“getState”和“setState”访问解析器操作中的当前状态。当你在一行开始时得到一系列“ - ”并将它与状态中的“深度”进行比较时,适当地操纵“nums”列表,然后以相反的顺序发出“nums”(我建议保留nums)以相反的顺序,因为大多数时候你想要访问最不重要的项目,所以把它放在列表的头部是更容易和更有效的。)
有关GenParser的详细信息,请参见Text.ParserCombinators.Parsec.Prim。更常见的Parser类型只是“类型Parser a = GenParser Char()a”你可能想说
type MyParser a = GenParser Char SectionState a
靠近代码开头的地方。