在StandardTokenParsers中使用正则表达式 [英] Using regex in StandardTokenParsers

查看:364
本文介绍了在StandardTokenParsers中使用正则表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在基于StandardTokenParsers的解析器中使用正则表达式.为此,我将StdLexical分为以下子类:

I'm trying to use regex in my StandardTokenParsers based parser. For that, I've subclassed StdLexical as follows:

class CustomLexical extends StdLexical{
  def regex(r: Regex): Parser[String] = new Parser[String] {
    def apply(in:Input) = r.findPrefixMatchOf(in.source.subSequence(in.offset, in.source.length)) match {
      case Some(matched) => Success(in.source.subSequence(in.offset, in.offset + matched.end).toString,
        in.drop(matched.end))
      case None => Failure("string matching regex `" + r + "' expected but " + in.first + " found", in)
    }
  }

  override def token: Parser[Token] =
    (   regex("[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r)     ^^ { StringLit(_) }
      | identChar ~ rep( identChar | digit )               ^^ { case first ~ rest => processIdent(first :: rest mkString "") }
      | ...

但是我对如何定义一个利用该特性的解析器感到有些困惑.我有一个解析器定义为:

But I'm a little confused on how I would define a Parser that takes advantage of this. I have a parser defined as:

def mTargetFolder: Parser[String] = "TargetFolder" ~> "=" ~> mFilePath

应用于标识有效的文件路径.然后我尝试了:

which should be used to identify valid file paths. I tried then:

def mFilePath: Parser[String] = "[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r

但这显然是不对的.我收到错误消息:

But this is obviously not right. I get an error:

scala: type mismatch;
 found   : scala.util.matching.Regex
 required: McfpDSL.this.Parser[String]
    def mFilePath: Parser[String] = "[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r
                                                                          ^

使用在StdLexical子类上进行的扩展的正确方法是什么?

What is the proper way of using the extension made on my StdLexical subclass?

推荐答案

如果您真的想使用基于令牌的解析,并重用StdLexical,我建议您更新"TargetFolder"的语法,以便等号后的值是正确的字符串文字.或者换句话说,做到这一点,所以路径应该用引号引起来.从那时起,您不再需要扩展StdLexical.

If you really want to use token based parsing, and reuse StdLexical, I would advise to update the syntax for "TargetFolder" so that the value after the equal sign is a proper string literal. Or in other words, make it so the path should be enclosed with quotes. From that point you don't need to extends StdLexical anymore.

然后是将正则表达式转换为解析器的问题. Scala已经为此提供了RegexParsers(将regexp隐式转换为Parser[String]),但是不幸的是,这不是您想要的,因为它适用于Char(RegexParsers中的type Elem = Char)流.致力于令牌的发展. 因此,我们确实必须定义自己的从Regex到Parser[String]的转换(但是在语法级别而不是词汇级别,或者换句话说,在令牌解析器中).

Then comes the problem of converting a regexp to a parser. Scala already has RegexParsers for this (which implicitly converts a regexp to a Parser[String]), but unfortunately that's not what you want here because it works on streams of Char (type Elem = Char in RegexParsers) while you are working on a sttream of tokens. So we will indeed have to define our own conversion from Regex to Parser[String] (but at the syntactic level rather than lexical level, or in other words in the token parser).

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

object MyParser extends StandardTokenParsers {
  import lexical.StringLit
  def regexStringLit(r: Regex): Parser[String] = acceptMatch( 
    "string literal matching regex " + r, 
    { case StringLit( s ) if r.unapplySeq(s).isDefined => s }
  )
  lexical.delimiters += "="
  lexical.reserved += "TargetFolder"
  lazy val mTargetFolder: Parser[String] = "TargetFolder" ~> "=" ~> mFilePath
  lazy val mFilePath: Parser[String] = regexStringLit("([a-zA-Z]:\\\\[\\w\\\\?]*)|(/[\\w/]*)".r)  
  def parseTargetFolder( s: String ) = { mTargetFolder( new lexical.Scanner( s ) ) }
}

示例:

scala> MyParser.parseTargetFolder("""TargetFolder = "c:\Dir1\Dir2" """)
res12: MyParser.ParseResult[String] = [1.31] parsed: c:\Dir1\Dir2

scala> MyParser.parseTargetFolder("""TargetFolder = "/Dir1/Dir2" """)
res13: MyParser.ParseResult[String] = [1.29] parsed: /Dir1/Dir2

scala> MyParser.parseTargetFolder("""TargetFolder = "Hello world" """)
res14: MyParser.ParseResult[String] =
[1.16] failure: identifier matching regex ([a-zA-Z]:\\[\w\\?]*)|(/[\w/]*) expected
TargetFolder = "Hello world"
           ^

请注意,这里还修复了目标文件夹"正则表达式,这两个选项周围缺少parens,以及不必要的空格.

Note that also fixed your "target folder" regexp here, you had missing parens around the two alternative, plus unneeded spaces.

这篇关于在StandardTokenParsers中使用正则表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆