代码之家  ›  专栏  ›  技术社区  ›  BefittingTheorem

访问scala解析器正则表达式匹配数据

  •  11
  • BefittingTheorem  · 技术社区  · 16 年前

    我想知道是否可以从下面的语法中匹配的正则表达式生成匹配数据。

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

    当然,一个选项是在块内再次执行匹配,但是由于regexparser已经执行了匹配,我希望它将匹配数据传递到块,或者存储它?

    4 回复  |  直到 15 年前
        1
  •  20
  •   Daniel C. Sobral    16 年前

    下面是隐式定义,它转换了 Regex 变成 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)
    
        2
  •  3
  •   David Winslow    16 年前

    不,你不能这样做。如果查看将regex转换为解析器时使用的解析器定义,它将丢弃所有上下文,并返回完全匹配的字符串:

    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)
      }
    

    这个 <~ 意思是“需要这两个令牌在一起,但只给出第一个令牌的结果。

    这个 ~ 意思是“需要这两个令牌在一起,并将它们绑在一个模式匹配的~对象中。

    这个 ? 意味着解析器是可选的,将返回一个选项。

    这个 .getOrElse 当解析器没有定义值时,bit提供一个默认值。

        3
  •  1
  •   Randall Schulz    16 年前

    当regex在regexparsers实例中使用时, 隐式def regex(regex):分析器[string] 在regexparsers中,用于将该regex应用于输入。成功应用当前输入处的re后生成的match实例用于在regex()方法中构造成功,但只使用其“end”值,因此在该方法返回时将丢弃所有捕获的子匹配。

    就目前情况而言(在我看过的2.7资料中),我相信你运气不好。

        4
  •  0
  •   Max    15 年前

    我使用scala 2.8.1遇到了类似的问题,并尝试使用 RegexParsers 班级:

    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))
      }
    }
    
    推荐文章