5

私は簡単な attoparsec パーサーを作成して、aspx ファイルを調べてすべてのスタイル属性を削除しましたが、>消費せずにマッチングを成功させる方法がわからない部分を除いて、正常に動作しています。

ここに私が持っているものがあります:

anyTill = manyTill anyChar
anyBetween start end = start *> anyTill end

styleWithQuotes = anyBetween (stringCI "style=\"") (stringCI "\"")
styleWithoutQuotes = anyBetween (stringCI "style=") (stringCI " " <|> ">")
everythingButStyles = manyTill anyChar (styleWithQuotes <|> styleWithoutQuotes) <|> many1 anyChar

私はそれが部分的に私がeverythingButStylesでmanyTillをどのように使用しているかを理解していますstyleWithoutQuotes.私はちょうどやっlookAhead ">"たでしょうが、attoparsecではそれができません。

4

2 に答える 2

5

一方、コンビネータがattoparseclookAheadに追加されたため、 orを使用して目標を達成できるようになりました。lookAhead (char '>')lookAhead (string ">")

以下は、導入前の時代からの回避策です。


を使用して、消費しないパーサーを構築できますpeekWord8。これは、次のバイト (存在する場合) を調べるだけです。インスタンスをByteString持っているので、 であり、使用できますMonoidParser ByteStringMonadPlus

lookGreater = do
    mbw <- peekWord8
    case mbw of
      Just 62 -> return ">"
      _ -> mzero

(62 は のコード ポイントです) を消費せずに'>'見つけるか、失敗します。'>'

于 2012-11-02T23:08:42.587 に答える
5
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"場合はバックトラックしてすべてを取得することを意味する方法で使用します。これは、遅くなる可能性のある種類のものの例です。問題は、入力文字列の最後で失敗することです。これは、失敗するかどうかを選択するのに適していません。全力でやってみよう

  1. 失敗するならすぐに失敗しましょう。
  2. Data.Attoparsec.Text.Internalの高速パーサーを最大限に活用する

アイデア: s が得られるまで取り、そこにスタイルがある場合はスキップします。

notStyleNotEvenS = takeTill (flip elem "sS") 
skipAnyStyle = (styleWithQuotes' <|> styleWithoutQuotes') *> notStyleNotEvenS 
               <|> cons <$> anyChar <*> notStyleNotEvenS

anyChar通常sorSですが、もう一度確認しても意味がありません。

noStyles = append <$> notStyleNotEvenS <*> many skipAnyStyle 

parseNoStyles = parseOnly noStyles
于 2012-11-02T23:57:32.410 に答える