Data.Attoparsec.Text
エクスポートtakeWhile
とtakeWhile1
:
takeWhile :: (Char -> Bool) -> Parser Text
述語が を返す限り入力を消費し
True
、消費された入力を返します。このパーサーは失敗しません。
False
入力の最初の文字で述語が返される場合、空の文字列が返されます。[...]
takeWhile1 :: (Char -> Bool) -> Parser Text
述語が を返す限り入力を消費し
True
、消費された入力を返します。このパーサーは、入力の少なくとも 1 文字で成功する述語を必要とします。述語が返されない場合、
True
または入力が残っていない場合、失敗します。
attoparsec
のドキュメンテーションは、ユーザーに
の代わりに、
Text
可能な限り 指向のパーサーを使用してください。2 種類のパーサーのパフォーマンスには約 100 倍の違いがあります。takeWhile1
many1 anyChar
takeWhile1
これらの 2 つのパーサーは非常に便利ですが、より一般的なバージョンの、より具体的には、仮説パーサーの必要性を常に感じています。
takeWhileLo :: (Char -> Bool) -> Int -> Parser Text
takeWhileLo f lo = undefined
predicate を満たす文字を少なくとも 解析します。ここで、 は任意の非負の整数です。lo
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
そのようなコンビネータを実装するより効率的/慣用的な方法はありますか?