11

I wondering if it's possible to get the MatchData generated from the matching regular expression in the grammar below.

object DateParser extends JavaTokenParsers {

    ....

    val dateLiteral = """(\d{4}[-/])?(\d\d[-/])?(\d\d)""".r ^^ {
        ... get MatchData
    }
}

One option of course is to perform the match again inside the block, but since the RegexParser has already performed the match I'm hoping that it passes the MatchData to the block, or stores it?

4

4 に答える 4

20

Regexyourを aに変換する暗黙の定義は次のParserとおりです。

  /** A parser that matches a regex string */
  implicit def regex(r: Regex): Parser[String] = new Parser[String] {
    def apply(in: Input) = {
      val source = in.source
      val offset = in.offset
      val start = handleWhiteSpace(source, offset)
      (r findPrefixMatchOf (source.subSequence(start, source.length))) match {
        case Some(matched) =>
          Success(source.subSequence(start, start + matched.end).toString, 
                  in.drop(start + matched.end - offset))
        case None =>
          Failure("string matching regex `"+r+"' expected but `"+in.first+"' found", in.drop(start - offset))
      }
    }
  }

それを適応させるだけです:

object X extends RegexParsers {
  /** A parser that matches a regex string and returns the Match */
  def regexMatch(r: Regex): Parser[Regex.Match] = new Parser[Regex.Match] {
    def apply(in: Input) = {
      val source = in.source
      val offset = in.offset
      val start = handleWhiteSpace(source, offset)
      (r findPrefixMatchOf (source.subSequence(start, source.length))) match {
        case Some(matched) =>
          Success(matched,
                  in.drop(start + matched.end - offset))
        case None =>
          Failure("string matching regex `"+r+"' expected but `"+in.first+"' found", in.drop(start - offset))
      }
    }
  }
  val t = regexMatch("""(\d\d)/(\d\d)/(\d\d\d\d)""".r) ^^ { case m => (m.group(1), m.group(2), m.group(3)) }
}

例:

scala> X.parseAll(X.t, "23/03/1971")
res8: X.ParseResult[(String, String, String)] = [1.11] parsed: (23,03,1971)
于 2009-11-29T17:06:14.760 に答える
3

いいえ、これはできません。正規表現をパーサーに変換するときに使用されるパーサーの定義を見ると、すべてのコンテキストが破棄され、完全に一致した文字列が返されます。

http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/library/scala/util/parsing/combinator/RegexParsers.scala?view=markup#L55

ただし、他にもいくつかのオプションがあります。

  • パーサーをいくつかの小さなパーサーに分割します(実際に抽出したいトークン用)
  • 必要な値を抽出し、文字列の代わりにドメインオブジェクトを返すカスタムパーサーを定義します

最初は次のようになります

val separator = "-" | "/"
  val year = ("""\d{4}"""r) <~ separator
  val month = ("""\d\d"""r) <~ separator
  val day = """\d\d"""r

  val date = ((year?) ~ (month?) ~ day) map {
    case year ~ month ~ day =>
      (year.getOrElse("2009"), month.getOrElse("11"), day)
  }

これ<~は、「これら2つのトークンを一緒に必要としますが、最初のトークンの結果のみを提供する」という意味です。

これ~は、「これら2つのトークンを一緒に必要とし、パターンが一致する〜オブジェクトでそれらを結び付ける」という意味です。

?パーサーはオプションであり、オプションを返すことを意味します。

この.getOrElseビットは、パーサーが値を定義しなかった場合のデフォルト値を提供します。

于 2009-11-29T16:01:59.843 に答える
1

RegexParsers インスタンスで Regex が使用される場合、RegexParsers の暗黙的な def regex(Regex): Parser[String]を使用して、その Regex が入力に適用されます。現在の入力で RE の適用が成功したときに生成された Match インスタンスは、regex() メソッドで Success を構築するために使用されますが、その「終了」値のみが使用されるため、キャプチャされたサブマッチはそのメソッドまでに破棄されます。戻り値。

現状 (私が見た 2.7 のソース) では、運が悪いと思います。

于 2009-11-29T15:48:14.057 に答える
0

RegexParsersscala 2.8.1 を使用して同様の問題に遭遇し、クラスを使用して「name:value」形式の入力を解析しようとしました。

package scalucene.query

import scala.util.matching.Regex
import scala.util.parsing.combinator._

object QueryParser extends RegexParsers {
  override def skipWhitespace = false

  private def quoted = regex(new Regex("\"[^\"]+"))
  private def colon = regex(new Regex(":"))
  private def word = regex(new Regex("\\w+"))
  private def fielded = (regex(new Regex("[^:]+")) <~ colon) ~ word
  private def term = (fielded | word | quoted)

  def parseItem(str: String) = parse(term, str)
}

次のように解析した後、一致したグループを取得できるようです。

QueryParser.parseItem("nameExample:valueExample") match {
  case QueryParser.Success(result:scala.util.parsing.combinator.Parsers$$tilde, _) => {
      println("Name: " + result.productElement(0) + " value: " + result.productElement(1))
  }
}
于 2011-03-06T06:32:19.570 に答える