Data.Attoparsec.Text
出口takeWhile
和takeWhile1
:
takeWhile :: (Char -> Bool) -> Parser Text
只要谓词返回
True
,就消费输入,并返回消费的输入。此解析器不会失败。
False
如果谓词在输入的第一个字符上返回,它将返回一个空字符串。[...]
takeWhile1 :: (Char -> Bool) -> Parser Text
只要谓词返回
True
,就消费输入,并返回消费的输入。此解析器要求谓词在至少一个输入字符上成功:如果谓词永远不会返回
True
或没有输入,它将失败。
attoparsec
的文档鼓励用户
Text
尽可能使用面向- 的解析器,例如,takeWhile1
而不是many1 anyChar
. 两种解析器之间的性能差异大约为 100 倍。
这两个解析器非常有用,但我一直觉得需要一个更通用的版本takeWhile1
,更具体地说,一些假设的解析器
takeWhileLo :: (Char -> Bool) -> Int -> Parser Text
takeWhileLo f lo = undefined
这将至少 解析lo
满足 predicate 的字符f
,其中lo
是任意非负整数。
我查看了takeWhile1
的实现,但它使用了一堆私有的函数,Data.Attoparsec.Text.Internal
并且似乎不容易推广。
我想出了以下应用实现:
{-# LANGUAGE OverloadedStrings #-}
import Prelude hiding ( takeWhile )
import Control.Applicative ( (<*>) )
import Data.Text ( Text )
import qualified Data.Text as T
import Data.Attoparsec.Text
takeWhileLo :: (Char -> Bool) -> Int -> Parser Text
takeWhileLo f lo =
T.append . T.pack <$> count lo (satisfy f) <*> takeWhile f
它像宣传的那样工作,
λ> parseOnly (takeWhileLo (== 'a') 4) "aaa"
Left "not enough input"
λ> parseOnly (takeWhileLo (== 'a') 4) "aaaa"
Right "aaaa"
λ> parseOnly (takeWhileLo (== 'a') 4) "aaaaaaaaaaaaa"
Right "aaaaaaaaaaaaa"
但是需要打包返回的结果的中间列表count
让我担心,特别是对于lo
很大的情况......这似乎与建议背道而驰
Text
尽可能使用面向- 的解析器 [...]
我错过了什么吗?有没有更有效/惯用的方式来实现这样的takeWhileLo
组合器?