Jim*_*ffa 5 parsing haskell attoparsec
我写了一个快速的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
Run Code Online (Sandbox Code Playgroud)
我理解这部分是因为我在everythingButStyles中如何使用manyTill,这就是我如何积极地放弃所有样式的东西,但是styleWithoutQuotes我需要它来匹配">"作为结束,但不要消耗它,在parsec中我会做,lookAhead ">"但我不能在attoparsec做到这一点.
同时,在attoparseclookAhead中添加了组合子,所以现在可以使用lookAhead (char '>')或lookAhead (string ">")来实现目标。
以下是其引入之前的解决方法。
您可以使用 构建您的非消费解析器peekWord8,它只查看下一个字节(如果有)。由于ByteString有一个Monoid实例,Parser ByteString是 a MonadPlus,您可以使用
lookGreater = do
mbw <- peekWord8
case mbw of
Just 62 -> return ">"
_ -> mzero
Run Code Online (Sandbox Code Playgroud)
(62 是 ) 的代码点,'>'要么在'>'不消耗它的情况下找到它,要么失败。
anyBetween start end = start *> anyTill end
Run Code Online (Sandbox Code Playgroud)
你的anyBetween解析器会吃它的最后一个字符,因为anyTill它 - 它被设计为解析一个结束标记,但假设你不想让输入中的右括号再次解析.
请注意,您的end解析器都是单字符解析器,因此我们可以更改功能以使用它:
anyBetween'' start ends = start *> many (satisfy (not.flip elem ends))
Run Code Online (Sandbox Code Playgroud)
但是many效率不如Attoparsec takeWhile,你应该尽可能多地使用它,所以如果你已经完成了
import qualified Data.Attoparsec.Text as A
Run Code Online (Sandbox Code Playgroud)
然后
anyBetween' start ends = start *> A.takeWhile (not.flip elem ends)
Run Code Online (Sandbox Code Playgroud)
应该做的伎俩,我们可以重写
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
Run Code Online (Sandbox Code Playgroud)
如果你想要它吃' '但不是'>'你可以事后明确地吃空间:
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
<* A.takeWhile isSpace
Run Code Online (Sandbox Code Playgroud)
takeWhile或许styleWithQuotes也可以用重写来使用takeWhile,所以让我们做两个帮助anyBetween.它们从起始解析器到结束字符,并且有包容性和独占版本:
fromUptoExcl startP endChars = startP *> takeTill (flip elem endChars)
fromUptoIncl startP endChars = startP *> takeTill (flip elem endChars) <* anyChar
Run Code Online (Sandbox Code Playgroud)
但我想从你所说的,你想styleWithoutQuotes成为一个混合体; 它吃' '但不吃>:
fromUptoEat startP endChars eatChars =
startP
*> takeTill (flip elem endChars)
<* satisfy (flip elem eatChars)
Run Code Online (Sandbox Code Playgroud)
(所有这些都假设您的结束字符列表中有少量字符,否则elem效率不高 - Set如果您检查字母表之类的大列表,则会有一些变体.)
现在重写:
styleWithQuotes' = fromUptoIncl (stringCI "style=\"") "\""
styleWithoutQuotes' = fromUptoEat (stringCI "style=") " >" " "
Run Code Online (Sandbox Code Playgroud)
everythingButStyles使用<|>方式意味着如果它没有找到"style"它将回溯然后采取一切.这是一个可能很慢的事情的例子.问题是我们迟到了 - 在输入字符串的末尾,这是一个关于我们是否应该失败的选择的不好时机.让我们全力以赴,努力
想法:直到我们得到一个s,然后跳过风格,如果那里有一个.
notStyleNotEvenS = takeTill (flip elem "sS")
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS
<|> cons <$> anyChar <*> notStyleNotEvenS
Run Code Online (Sandbox Code Playgroud)
在anyChar通常是一个s或S,但没有感觉再次检查.
noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle
parseNoStyles = parseOnly noStyles
Run Code Online (Sandbox Code Playgroud)