如何使Attoparsec解析器成功而不消耗(如秒差距预读)(How do I make Attop

2019-08-02 05:58发布

我写了一个快速attoparsec解析器走一个aspx文件并删除所有样式属性,它的工作,除了一张;得很好,我无法弄清楚如何使它匹配成功>不消耗它。

下面是我有:

anyTill = manyTill anyChar
anyBetween start end = start *> anyTill end

styleWithQuotes = anyBetween (stringCI "style=\"") (stringCI "\"")
styleWithoutQuotes = anyBetween (stringCI "style=") (stringCI " " <|> ">")
everythingButStyles = manyTill anyChar (styleWithQuotes <|> styleWithoutQuotes) <|> many1 anyChar

我知道这是因为我是如何在everythingButStyles使用manyTill的部分,那就是如何我积极未落到地面的所有样式的东西,但在styleWithoutQuotes我需要它来搭配“>”作为结束,但不能消耗它,在秒差距我刚做lookAhead ">"但我不能这样做,在attoparsec。

Answer 1:

同时, lookAhead加入组合子到attoparsec ,所以现在可以只使用lookAhead (char '>')lookAhead (string ">")要达到的目标。

下面是其推出前的时间解决方法。


您可以通过建立自己的非消耗解析器peekWord8 ,这只是着眼于下一个字节(如果有的话)。 由于ByteStringMonoid实例, Parser ByteStringMonadPlus ,并且可以使用

lookGreater = do
    mbw <- peekWord8
    case mbw of
      Just 62 -> return ">"
      _ -> mzero

(62是的编码点'>' ),以找到一条'>'不消耗它或失败。



Answer 2:

anyBetween start end = start *> anyTill end

anyBetween解析器吃它的最后一个字符,因为anyTill那样-它的设计解析高达结束标志,但假设你不想保持在大括号中输入再次解析。

请注意,您的end解析器都是单个字符解析器,所以我们可以通过改变功能,利用这样的:

anyBetween'' start ends = start *> many (satisfy (not.flip elem ends))

many并不像Attoparsec的高效takeWhile ,你应该使用尽可能多的,所以如果你已经做了

import qualified Data.Attoparsec.Text as A

然后

anyBetween' start ends = start *> A.takeWhile (not.flip elem ends)

应该做的伎俩,我们可以重写

styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']

如果你想要吃' '而不是'>'你可以明确地吃空间算账:

styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>'] 
                     <* A.takeWhile isSpace

去为更多takeWhile

也许styleWithQuotes可以与重写使用做takeWhile一样,所以让我们上线两个帮手anyBetween 。 他们从一开始解析器长达一个结束字符,而且有包容性和排他性的版本:

fromUptoExcl startP endChars = startP *> takeTill (flip elem endChars)
fromUptoIncl startP endChars = startP *> takeTill (flip elem endChars) <* anyChar

但是我觉得从你说,你要styleWithoutQuotes是一个混合; 它吃' '而不是>

fromUptoEat startP endChars eatChars = 
            startP 
            *> takeTill (flip elem endChars) 
            <* satisfy (flip elem eatChars)

(所有这些假设少数在结束字符列表的字符,否则elem效率不高-有一些Set变种,如果你对检查的大名单就像一个字母)。

现在的改写:

styleWithQuotes' = fromUptoIncl (stringCI "style=\"") "\""
styleWithoutQuotes' = fromUptoEat (stringCI "style=") " >" " "

总体解析器

everythingButStyles用途<|>在这意味着,如果它没有找到一个方法"style"会原路返回然后采取一切。 这是诸如此类的事情,这可能是缓慢的一个例子。 问题是,我们不迟到 - 输入字符串,这是一个不好的时候做一个关于我们是否应该失败选择结束。 让我们全力以赴,并尝试

  1. 失败立刻如果我们注定会失败。
  2. 最大限度地利用从快解析器Data.Attoparsec.Text.Internal

理念:走,直到我们得到一个s,然后跳过风格,如果有一个人也没有。

notStyleNotEvenS = takeTill (flip elem "sS") 
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS 
               <|> cons <$> anyChar <*> notStyleNotEvenS

anyChar通常是一个sS ,但没有感觉再次检查。

noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle 

parseNoStyles = parseOnly noStyles


文章来源: How do I make Attoparsec parser succeed without consuming (like parsec lookAhead)