16

Parsec で初めてのプログラムを書いています。私は MySQL スキーマ ダンプを解析したいと考えており、特定のキーワードを表す文字列を大文字と小文字を区別しない方法で解析するための優れた方法を考え出そうとしています。「CREATE」または「create」を解析するために使用しているアプローチを示すコードを次に示します。これを行うより良い方法はありますか?buildExpressionParser に頼らない回答が最適です。私はここで赤ちゃんの一歩を踏み出しています。

  p_create_t :: GenParser Char st Statement
  p_create_t = do
      x <- (string "CREATE" <|> string "create")
      xs <- manyTill anyChar (char ';')
      return $ CreateTable (x ++ xs) []  -- refine later
4

5 に答える 5

20

文字パーサーから大文字と小文字を区別しないパーサーを構築できます。

-- Match the lowercase or uppercase form of 'c'
caseInsensitiveChar c = char (toLower c) <|> char (toUpper c)

-- Match the string 's', accepting either lowercase or uppercase form of each character 
caseInsensitiveString s = try (mapM caseInsensitiveChar s) <?> "\"" ++ s ++ "\""
于 2012-10-17T16:24:41.380 に答える
8

明らかに役に立ったので、コメントで言ったことを繰り返します。

ここでの単純な大ハンマー ソリューションはtoLower、パーサーを実行する前に入力全体を単純にマップし、すべてのキーワード マッチングを小文字で行うことです。

これは、ある場所では大文字と小文字を区別せず、別の場所では大文字と小文字を区別する必要があるものを解析している場合、または見た目上の理由で大文字と小文字を保持することに関心がある場合、明らかに困難です。たとえば、HTML タグは大文字と小文字を区別しませんが、解析中に Web ページ全体を小文字に変換することはおそらく望ましくありません。大文字と小文字を区別しないプログラミング言語をコンパイルする場合でも、結果として生じるエラー メッセージはプログラマーが書いたものと一致しないため、識別子の変換は面倒な場合があります。

于 2012-10-17T15:43:37.343 に答える
3

いいえ、Parsec はクリーンな方法でそれを行うことはできません。等価性テストを使用するようにハードコーディングされた stringプリミティブ コンビネータの上に実装されます。大文字と小文字を区別しない文字を解析する方が少し簡単ですが、おそらくもっと多くのことが必要になるでしょう。tokens(==)

ただし、必要なすべてのソリューションが組み込まれているMegaparsecと呼ばれる、Parsec の最新のフォークがあり ます。

λ> parseTest (char' 'a') "b"
parse error at line 1, column 1:
unexpected 'b'
expecting 'A' or 'a'
λ> parseTest (string' "foo") "Foo"
"Foo"
λ> parseTest (string' "foo") "FOO"
"FOO"
λ> parseTest (string' "foo") "fo!"
parse error at line 1, column 1:
unexpected "fo!"
expecting "foo"

最後のエラー メッセージに注意してください。これは、文字を 1 つずつ解析して取得できるものよりも優れています (特に、特定のケースで役立ちます)。string' Parsec と同じように実装されてstringいますが、大文字と小文字を区別しない比較を使用して文字を比較します。また、場合によってはそれが役立つ場合もありますoneOf'noneOf'


開示: 私は Megaparsec の作成者の 1 人です。

于 2015-09-25T17:12:13.553 に答える
0

入力全体を でマッピングする代わりに、from (hsemail パッケージから)toLowerを使用することを検討してください。caseStringText.ParserCombinators.Parsec.Rfc2234

Text.ParsecCombinators.Parsec.Rfc2234

p_create_t :: GenParser Char st Statement
p_create_t = do
  x <- (caseString "create")
  xs <- manyTill anyChar (char ';')
  return $ CreateTable (x ++ xs) []  -- refine later

したがってx、入力を変更せずに、入力に存在するケースバリアントは何でもなります。

ps:これは古い質問であることは知っています。同様の問題を探しているときにこの質問が出てきたので、これを追加すると思いました

于 2015-05-24T00:16:16.327 に答える