2017-04-07 81 views
2

在正則表達式中,您可以通過執行類似\d{1,5}這樣的操作來獲取一個解析範圍,該解析器可以貪婪地解析數字1到5次。或者你做\d{1,5}?使它懶惰。Haskell文本解析器組合器解析範圍貪婪像正則表達式範圍表示法

你如何在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],你會得到一個懶惰的解析。

是否有更好或更習慣的方法來解析器組合?

回答

1

更新:下面是錯誤的 - 例如 rangeGreedy 2 4 a <* string "aab",正則表達式a{2,4}aab相當於不匹配。提問者的解決方案正確。我不會刪除答案,以防止其他人犯同樣的錯誤。

=========

這不是一個完整的答案,只是寫的貪婪 版本一個可行的辦法。我還沒有找到一個很好的方式來做懶惰的版本。

定義的option返回Maybes左偏版本:

greedyOption :: ReadP a -> ReadP (Maybe a) 
greedyOption p = (Just <$> p) <++ pure Nothing 

然後,我們可以做的最多的事情n,其中他們的replicateM

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"