2

HaskellとParsecは初めてです---この質問が些細なことならお詫びします。

次のように構成されたテキスト行を解析したいと思います。

<Text to be dropped> <special character (say "#")> <field 1> <comma> <field 2>
<comma> <field 3> <special character 2 (say "%")> <Text to be dropped>

パーサーに、最初と最後に「ドロップするテキスト」を破棄し、フィールドの内容を保持してもらいたいです。私の主な問題は、特定の特殊な文字まですべてをドロップするパーサーを作成する方法を理解することです。

ライブラリのパーサーはanyChar、manyTill、oneOfですが、それらを組み合わせる方法がわかりません。簡単な例をいただければ幸いです。

4

2 に答える 2

4

Parsec コードを書くときは、解析したい文法を最初にBNF形式で書き出すと便利です。なぜなら、Parsec で書かれたパーサーは最終的に文法に非常によく似たものになるからです。

それを試してみましょう:

line ::= garbage '#' field ',' field ',' field '%' garbage

上記のプロダクションでは、 という名前のプロダクションを想定しgarbageています。その実際の定義は、実際にドロップしたいテキストによって異なります。同様に、 という名前のプロダクションを想定していfieldます。それでは、この生成物をパーセク コードとして書き出しましょう。

line = do
  garbage
  char '#'
  field1 <- field
  char ','
  field2 <- field
  char ','
  field3 <- field
  char '%'
  garbage
  return (field1, field2, field3)

このコードは、BNF とまったく同じように読み取ります。本質的な違いは、一部のサブプロダクションの結果に名前が付けられているため、これらの結果から構築された値 (この場合はタプル) を返すことができることです。

ガベージの概念が何であるかはわかりませんが、例のために、空白を意味すると仮定しましょう。garbage次に、次のように定義できます。

garbage = many space

(あるいは、 parsec が と呼ばれる 0 個以上のスペースを解析するためのコンビネータを既に持っている場合もありますspaces)。ガベージが区切り文字以外の何かである可能性がある場合、次の#ように言うことができます

garbage = many (noneOf "#")

この行は、最初の「#」までのすべての入力をむしゃむしゃ食べます。いずれにせよgarbage、名前を値にバインドしていないため、結果として生成される値は破棄されます。

于 2012-10-04T16:31:21.613 に答える
1

または、アプリケーション パーサーを使用できます。

import Control.Applicative
import Text.Parsec
import Text.Parsec.String

type Field = ()                 --your type here

field = string "()" *> pure ()  --your parser here

parser :: Parser (Field, Field, Field)
parser = manyTill anyChar (char '#') *>
         ((,,) <$> (field <* char ',')
               <*> (field <* char ',')
               <*> (field <* char '%'))
于 2012-10-04T16:49:21.010 に答える