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
それから
anyBetween' start ends = start *> A.takeWhile (not.flip elem ends)
トリックを行う必要があり、書き換えることができます
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
を食べたいが、を食べたくない場合は' '
、'>'
後で明示的にスペースを食べることができます:
styleWithoutQuotes = anyBetween' (stringCI "style=") [' ','>']
<* A.takeWhile isSpace
もっと見るtakeWhile
おそらくstyleWithQuotes
、書き直して使用することtakeWhile
もできるので、 の行に 2 つのヘルパーを作成しましょうanyBetween
。それらは、開始パーサーから終了文字までを取得し、包括的バージョンと排他的バージョンがあります。
fromUptoExcl startP endChars = startP *> takeTill (flip elem endChars)
fromUptoIncl startP endChars = startP *> takeTill (flip elem endChars) <* anyChar
しかし、あなたが言ったことから、あなたstyleWithoutQuotes
はハイブリッドになりたいと思います。食べますが食べ' '
ません>
:
fromUptoEat startP endChars eatChars =
startP
*> takeTill (flip elem endChars)
<* satisfy (flip elem eatChars)
(これらはすべて、最後の文字リストに少数の文字があることを前提としています。それ以外の場合elem
は効率的ではありませんSet
。アルファベットのような大きなリストに対してチェックする場合は、いくつかのバリエーションがあります。)
書き換えのために:
styleWithQuotes' = fromUptoIncl (stringCI "style=\"") "\""
styleWithoutQuotes' = fromUptoEat (stringCI "style=") " >" " "
全体的なパーサー
everythingButStyles
<|>
見つからない"style"
場合はバックトラックしてすべてを取得することを意味する方法で使用します。これは、遅くなる可能性のある種類のものの例です。問題は、入力文字列の最後で失敗することです。これは、失敗するかどうかを選択するのに適していません。全力でやってみよう
- 失敗するならすぐに失敗しましょう。
- Data.Attoparsec.Text.Internalの高速パーサーを最大限に活用する
アイデア: s が得られるまで取り、そこにスタイルがある場合はスキップします。
notStyleNotEvenS = takeTill (flip elem "sS")
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS
<|> cons <$> anyChar <*> notStyleNotEvenS
はanyChar
通常s
orS
ですが、もう一度確認しても意味がありません。
noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle
parseNoStyles = parseOnly noStyles