3

単純なパーサー コンビネーターを試してみると、コンパイル エラーが発生します。

「スミス、ジョー」を Name(Joe、Smith) のような名前オブジェクトに解析したいと思います。十分に単純だと思います。

これに関連するコードは次のとおりです。

    import util.parsing.combinator._

    class NameParser extends JavaTokenParsers {
      lazy val name: Parser[Name] = 
        lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}
      lazy val lastName = stringLiteral
      lazy val firstName = stringLiteral
    }

    case class Name(firstName:String, lastName: String)

そして、私はそれを介してテストしています

object NameParserTest {
  def main(args: Array[String]) {
    val parser = new NameParser()
    println(parser.parseAll(parser.name, "Schmo, Joe"))
  }
}

コンパイル エラーの取得:

error: constructor cannot be instantiated to expected type;
found   : NameParser.this.~[a,b]
required: java.lang.String
lazy val name: Parser[Name] = lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}

ここで私が見逃しているのは何ですか?

4

3 に答える 3

8

この行で:

  lazy val name: Parser[Name] = 
    lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}

<~と の両方を使用したくありません~>","andfirstNameと keep のみに一致するパーサーを作成し、さらに と前のパーサー","に一致して のみを保持するパーサーを作成しています。lastNamelastName

これを次のように置き換えることができます。

(lastName <~ ",") ~ firstName ^^ {case (l ~ f) => Name(f, l)}

ただし、これは希望どおりにコンパイルおよび結合されますが、希望どおりに解析されません。試したところ、次の出力が得られました。

[1.1] failure: string matching regex `"([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*"' expected but `S' found

Schmo, Joe
^

stringLiteralコード内の文字列リテラルのように見えるもの (引用符で囲まれたもの) が必要です。(JavaTokenParsersJavaのように見えるものを解析するためのものです。)これは機能します:

scala> val x = new NameParser
x: NameParser = NameParser@1ea8dbd

scala> x.parseAll(x.name, "\"Schmo\", \"Joe\"")
res0: x.ParseResult[Name] = [1.15] parsed: Name("Joe","Schmo")

おそらく、名前として受け入れる文字列の種類を指定する正規表現に置き換える必要があります。こちらのドキュメントを見ると、次のことがわかります。

implicit def regex (r: Regex) : Parser[String]

A parser that matches a regex string

したがって、そこにオブジェクトを配置するだけRegexで、それに一致するパーサーに変換されます。

于 2011-04-23T19:08:35.457 に答える
7

~>コンビネータは左側を無視し、コンビネータ<~は右側を無視します。したがって、の結果にとの両方の結果を含めることはできlastName <~ "," ~> firstNameません。実際には、無視されるため、の解析結果のみです。ここではシーケンシャルコンポジションを使用する必要があります。firstNamelastNamelastName"," ~> firstName

lazy val name: Parser[Name] =         
  lastName ~ "," ~ firstName ^^ {case (l ~_~ f) => Name(f, l)}

または、よりきれいなパターンマッチが必要な場合:

lazy val name: Parser[Name] =         
  lastName ~ ("," ~> firstName) ^^ {case (l ~ f) => Name(f, l)}
于 2011-04-23T18:56:19.227 に答える
4

コード

lastName <~ "," ~> firstName

解析の結果を破棄することになりますfirstName。Scalaの演算子の優先順位規則により、ステートメントは次のように括弧で囲まれているかのように解析されます。

lastName <~ ("," ~> firstName)

ただし、グループ化が異なっていても、3つのパーサーのみを処理し、そのうちの2つのパーサーの結果を破棄しているだけです。

したがって、代わりStringに期待するように記述されたマッピング関数に渡されることになります。~[String, String]そのため、コンパイラエラーが発生します。

この種のトラブルシューティングに役立つテクニックの1つは、部分式に属性を追加することです。

lazy val name: Parser[Name] =
  ((lastName <~ "," ~> firstName): Parser[String ~ String]) ^^ { case l ~ f => Name(f, l) }

これは、現実と期待がどこで分岐しているかを正確に判断するのに役立ちます。

于 2011-04-23T19:00:52.100 に答える