在正则表达式中,您可以通过执行\d{1,5}
之类的操作来获取一系列解析,这些数据会贪婪地解析数字1至5次。或者你\d{1,5}?
让它变得懒惰。
你如何在Haskell的Text.ParserCombinators.ReadP中做到这一点?
我的尝试给了这个:
rangeParse :: Read a => ReadP a -> [Int] -> ReadP [a]
rangeParse parse ranges = foldr1 (<++) $ fmap (\n -> count n $ parse) ranges
如果您像rangeParse (satisfy isDigit) ([5,4..1])
那样执行此操作,则会执行1到5次贪婪的数字分析。如果你将数字序列交换为[1..5]
,则会得到一个懒惰的解析。
使用解析器组合器是否有更好或更惯用的方法?
答案 0 :(得分:1)
更新:以下是错误的 - 例如
rangeGreedy 2 4 a <* string "aab"
,相当于正则表达式a{2,4}aab
,并不匹配。提问者的解决方案是正确的。我不会删除答案,以防万一其他人犯同样的错误。
======
这不是一个完整的答案,只是一种写贪婪的可能方式 版。我还没有找到一个很好的方法来做懒人版本。
定义一个返回Maybes的左侧偏向版option
:
greedyOption :: ReadP a -> ReadP (Maybe a)
greedyOption p = (Just <$> p) <++ pure Nothing
然后,我们可以使用replicateM
来完成n的某些事情:
upToGreedy :: Int -> ReadP a -> ReadP [a]
upToGreedy n p = catMaybes <$> replicateM n (greedyOption p)
要允许最小计数,请单独执行必需部分并追加 它:
rangeGreedy :: Int -> Int -> ReadP a -> ReadP [a]
rangeGreedy lo hi p = (++) <$> count lo p <*> upToGreedy (hi - lo) p
我的测试代码的其余部分,以防对任何人有用:
module Main where
import Control.Monad (replicateM)
import Data.Maybe (catMaybes)
import Text.ParserCombinators.ReadP
main :: IO ()
main = mapM_ go ["aaaaa", "aaaab", "aaabb", "aabbb", "abbbb", "bbbbb"]
where
go = print . map fst . readP_to_S test
test :: ReadP [String]
test = ((++) <$> rangeGreedy 2 4 a <*> many aOrB) <* eof
where
a = char 'a' *> pure "ay"
aOrB = (char 'a' +++ char 'b') *> pure "ayorbee"