Parsing 如何在不消耗(如parsec lookAhead)的情况下使Attoparsec解析器成功
我编写了一个快速的attoparsec解析器来遍历一个aspx文件并删除所有的样式属性,它工作得很好,只是有一部分我不知道如何在不使用它的情况下成功地匹配Parsing 如何在不消耗(如parsec lookAhead)的情况下使Attoparsec解析器成功,parsing,haskell,attoparsec,Parsing,Haskell,Attoparsec,我编写了一个快速的attoparsec解析器来遍历一个aspx文件并删除所有的样式属性,它工作得很好,只是有一部分我不知道如何在不使用它的情况下成功地匹配 以下是我所拥有的: anyTill = manyTill anyChar anyBetween start end = start *> anyTill end styleWithQuotes = anyBetween (stringCI "style=\"") (stringCI "\"") styleWithoutQuotes =
以下是我所拥有的:
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
anyTill=manyTill anyChar
anyBetween start end=start*>anyTill end
styleWithQuotes=ANYBETH(stringCI“style=\”)(stringCI“\”)
styleWithoutQuotes=anyBetween(stringCI“style=)(stringCI”“”>)
everythingButStyles=manyTill anyChar(styleWithQuotes styleWithoutQuotes)many1 anyChar
我理解这部分是因为我在所有东西中都使用了manyTill,但是样式,这就是我如何积极地放弃所有样式的东西,但是在styleWithoutQuotes
中,我需要它匹配“>”作为结束,而不是使用它,在parsec中,我只需要做lookAhead”>
但我不能在atoparsec中实现这一点。同时,添加了组合符,因此现在可以使用前瞻(char'>')
或前瞻(string“>”
来实现目标
下面是《泰晤士报》推出前的一个变通方法
您可以使用构建非消费解析器,它只查看下一个字节(如果有)。由于
ByteString
有一个Monoid
实例,Parser ByteString
是一个MonadPlus
,您可以使用
lookGreater = do
mbw <- peekWord8
case mbw of
Just 62 -> return ">"
_ -> mzero
lookmorer=do
mbw返回“>”
_->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
然后
我们应该做到,我们可以重写
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
如果您想让它吃'
而不是'>'
,您可以在后面显式吃空格:
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
<* A.takeWhile isSpace
但我认为从你所说的来看,你希望样式不带引号
成为一个混合体;它吃'
,但不吃
:
fromUptoEat startP endChars eatChars =
startP
*> takeTill (flip elem endChars)
<* satisfy (flip elem eatChars)
整体解析器
everythingButStyles
使用
的方式意味着,如果找不到“style”
,它将回溯,然后获取所有内容。这是一个缓慢的例子。问题是我们失败得太晚——在输入字符串的末尾,这是一个不好的时机来选择是否应该失败。让我们全力以赴,努力
notStyleNotEvenS = takeTill (flip elem "sS")
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS
<|> cons <$> anyChar <*> notStyleNotEvenS
很好用!谢谢我想我可以用peek来做这个,但是我想不出如何让它返回正确的字符串类型(我现在必须去读关于mzero的书,我仍然不太熟悉所有的类型类和它们的实例。如果我强迫自己通过它,恐怕typeclassopedia会吞噬我的灵魂)最后你会找回你的灵魂。稍微改变。是的,我知道takeWhile应该更有效,但从我尝试做的事情来看,takeWhile似乎只允许在单个字节上进行匹配,而您可以看到,我的大多数匹配都是在字符串上进行的。我是否误解了如何使用takeWhile?谢谢你在这里的贡献well@JimmyHoffa您的开始都与字符串匹配(而且
string
是有效的,所以这没关系)。您的结尾(在示例代码中)都是单个字符,或者是其中的
s,这就是为什么我允许列出结尾字符。编辑澄清了吗?啊,你说得对。很酷,所以基本上很多和字符串都是你想要匹配很多字符串的正确方法,但是当你尝试匹配单字符时,获取和满足是正确的方法吗?@jimmyhoff。单次使用“满足”是可以的,但是当你想使用“满足”多个时,你应该使用takeWhile或takeTill。(也是新编辑。)由于styleWithQuotes'
和styleWithoutQuotes'
重叠(它们都是从解析字符串“style=”开始的),您还可以将styleWithQuotes'styleWithoutQuotes'
重构为一个解析器,以减少回溯的需要。哪种流类型(ByteString
或Text
)您使用的不清楚,但是,如果您使用的是文本,您应该使用ascicii
,而不是stringCI
;后者现在是。
fromUptoEat startP endChars eatChars =
startP
*> takeTill (flip elem endChars)
<* satisfy (flip elem eatChars)
styleWithQuotes' = fromUptoIncl (stringCI "style=\"") "\""
styleWithoutQuotes' = fromUptoEat (stringCI "style=") " >" " "
notStyleNotEvenS = takeTill (flip elem "sS")
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS
<|> cons <$> anyChar <*> notStyleNotEvenS
noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle
parseNoStyles = parseOnly noStyles