我写了一个快速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。
同时, lookAhead
加入组合子到attoparsec ,所以现在可以只使用lookAhead (char '>')
或lookAhead (string ">")
要达到的目标。
下面是其推出前的时间解决方法。
您可以通过建立自己的非消耗解析器peekWord8
,这只是着眼于下一个字节(如果有的话)。 由于ByteString
有Monoid
实例, Parser ByteString
是MonadPlus
,并且可以使用
lookGreater = do
mbw <- peekWord8
case mbw of
Just 62 -> return ">"
_ -> mzero
(62是的编码点'>'
),以找到一条'>'
不消耗它或失败。
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"
会原路返回然后采取一切。 这是诸如此类的事情,这可能是缓慢的一个例子。 问题是,我们不迟到 - 输入字符串,这是一个不好的时候做一个关于我们是否应该失败选择结束。 让我们全力以赴,并尝试
- 失败立刻如果我们注定会失败。
- 最大限度地利用从快解析器Data.Attoparsec.Text.Internal
理念:走,直到我们得到一个s,然后跳过风格,如果有一个人也没有。
notStyleNotEvenS = takeTill (flip elem "sS")
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS
<|> cons <$> anyChar <*> notStyleNotEvenS
该anyChar
通常是一个s
或S
,但没有感觉再次检查。
noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle
parseNoStyles = parseOnly noStyles
文章来源: How do I make Attoparsec parser succeed without consuming (like parsec lookAhead)