一个解析器,它接受Scala中的任何字符串?

时间:2014-02-28 12:25:52

标签: regex scala parsing parser-combinators

我正在为以下语法编写Scala解析器:

expr := "<" anyString ">" "<" anyString ">"
anyString := // any string

例如,"<foo> <bar>"是有效字符串,"<http://www.example.com/example> <123>""<1> <_hello>"

到目前为止,我有以下内容:

object MyParser extends JavaTokenParsers {

  override def skipWhitespace = false

  def expr: Parser[Any] = "<" ~ anyString ~ ">" ~ whiteSpace ~ "<" ~ anyString ~ ">"

  def anyString = ???

}

我的问题如下(我已经包含了我的怀疑答案,但无论如何,请确认,如果我是对的!):

  1. 如何实现接受任何字符串的正则表达式解析器?这必须有一个几乎无关紧要的答案,如def anyString = """\a*""".r,其中\a是代表任何字符的符号(虽然\a可能不是我正在寻找的机器人。)

  2. 如果我将anyString设置为接受任何字符串,它会在>符号之前停止,还是会一直运行直到字符串结束并失败?我相信它会一直运行到字符串结束并失败,然后它最终会找到>并消耗到那里。这似乎导致了一个非常低效的解析器,对此的任何评论都将受到赞赏!

  3. 如果<>中的字符串包含>符号(例如<fo>o> <bar>),该怎么办? anyString会消耗到第一个>还是最后一个?是否有任何方法可以指定它是否能消耗最少,或最多?

  4. 为了解决上一点问题,我想在<中禁止> anyString。怎么写呢?。

  5. 谢谢!

1 个答案:

答案 0 :(得分:1)

我正在研究自己的问题,我会在这里试着回答。

  1. Java Pattern documentation指定.匹配任何字符。因此,接受任何字符串的正则表达式将是:

    def anyString = ".*".r
    

    要接受任何非空字符串,我们可以使用".+".r

  2. 要理解这一点,请考虑以下玩具示例:

     object MyParser1 {
       override def skipWhitespace = false
       def expr = "<" ~ anyString ~ ">"
       def anyString = ".*".r
     }
    

    此处,字符串<>拒绝。要测试它,请使用:

    println(  MyParser1.parseAll(MyParser1.expr, "<>")  )
    

    这表示.*解析器正在消耗,直到字符串结束,因此>不可用于最终解析器。因此,似乎有必要禁止在<中出现>anyString表单。

  3. 与前一点一样,.*解析器使用整个字符串,因此会消耗所有>个符号。

  4. 在同一文档中,给出了否定运算符。要排除<>,我们可以写一下:

    def almostAnyString = "[^<>]*".r
    

    通常,构造[^abc]将匹配除 abc之外的任何字符

  5. 总而言之,到目前为止我发现的最佳实现如下:

    object MyParser extends JavaTokenParsers {
      override def skipWhitespace = false // don't allow whitespace between parsers by default
    
      def expr: Parser[Any] = "<" ~ almostAnyString ~ ">" ~
                              whiteSpace ~ // this parser is defined in JavaTokenParsers
                              "<" ~ almostAnyString ~ ">"
    
      def almostAnyString = "[^<>]*".r
    
    }