首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala Parser,为什么"pat <~ pat ~> pat“不起作用?

Scala Parser,为什么"pat <~ pat ~> pat“不起作用?
EN

Stack Overflow用户
提问于 2011-04-23 23:54:17
回答 3查看 625关注 0票数 3

尝试一个简单的解析器组合器,我遇到了编译错误。

我想把"Smith,Joe“解析成它的Name对象,比如Name(Joe,Smith)。我想,这很简单。

以下是与此相关的代码:

代码语言:javascript
复制
    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)

我正在测试它通过

代码语言:javascript
复制
object NameParserTest {
  def main(args: Array[String]) {
    val parser = new NameParser()
    println(parser.parseAll(parser.name, "Schmo, Joe"))
  }
}

获取编译错误:

代码语言:javascript
复制
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)}

我在这里遗漏了什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-04-24 03:08:35

在这里的这一行:

代码语言:javascript
复制
  lazy val name: Parser[Name] = 
    lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}

您不希望同时使用<~~>。您正在创建一个匹配","firstName的解析器,并且只保留",",然后创建一个匹配lastName和前一个解析器,并且只保留lastName的解析器。

您可以将其替换为:

代码语言:javascript
复制
(lastName <~ ",") ~ firstName ^^ {case (l ~ f) => Name(f, l)}

然而,尽管这将按照您想要的方式进行编译和组合,但它不会解析您想要的内容。当我尝试的时候,我得到了这个输出:

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

Schmo, Joe
^

stringLiteral需要代码中看起来像字符串文字的内容(引号中的内容)。(JavaTokenParsers旨在解析看起来像Java的东西。)这是可行的:

代码语言:javascript
复制
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")

您可能应该用一个正则表达式替换它,该正则表达式指定您将接受哪种类型的字符串作为名称。如果您查看文档here,您将看到:

代码语言:javascript
复制
implicit def regex (r: Regex) : Parser[String]

A parser that matches a regex string

因此,您只需在其中放置一个Regex对象,它将被转换为与之匹配的解析器。

票数 8
EN

Stack Overflow用户

发布于 2011-04-24 02:56:19

~>组合器忽略左侧,<~组合器忽略右侧。因此lastName <~ "," ~> firstName的结果永远不能同时包含firstNamelastName的结果。实际上这只是lastName的解析结果,因为"," ~> firstName被忽略了。您需要在此处使用顺序组合:

代码语言:javascript
复制
lazy val name: Parser[Name] =         
  lastName ~ "," ~ firstName ^^ {case (l ~_~ f) => Name(f, l)}

或者,如果你想要一个更漂亮的模式匹配:

代码语言:javascript
复制
lazy val name: Parser[Name] =         
  lastName ~ ("," ~> firstName) ^^ {case (l ~ f) => Name(f, l)}
票数 7
EN

Stack Overflow用户

发布于 2011-04-24 03:00:52

代码

代码语言:javascript
复制
lastName <~ "," ~> firstName

将最终丢弃解析firstName的结果。由于Scala中的运算符优先规则,对语句的解析就像它被放在括号中一样,如下所示:

代码语言:javascript
复制
lastName <~ ("," ~> firstName)

但是,即使它是以不同的方式分组的,您仍然只需要处理三个解析器,并丢弃其中两个解析器的结果。

因此,您最终会将一个String传递给映射函数,该函数被编写为期望一个~[String, String]。这就是为什么你会得到编译器错误的原因。

解决这类问题的一种有用的技术是向子表达式添加属性:

代码语言:javascript
复制
lazy val name: Parser[Name] =
  ((lastName <~ "," ~> firstName): Parser[String ~ String]) ^^ { case l ~ f => Name(f, l) }

这可以帮助你确定现实和你的期望到底有什么不同。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5765216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档