7

我是斯卡拉的新手。我正在尝试匹配由双引号分隔的字符串,但我对以下行为感到有些困惑:

如果我执行以下操作:

val stringRegex = """"([^"]*)"(.*$)"""
val regex = stringRegex.r
val tidyTokens = Array[String]("1", "\"test\"", "'c'", "-23.3")
tidyTokens.foreach {
    token => if (token.matches (stringRegex)) println (token + " matches!")
}

我明白了

"test" matches!

否则,如果我执行以下操作:

tidyTokens.foreach {
    token => token match {
        case regex(token) => println (token + " matches!")
        case _ => println ("No match for token " + token)
    }
}

我明白了

No match for token 1
No match for token "test"
No match for token 'c'
No match for token -23.3

为什么在第二种情况下“测试”不匹配?

4

1 回答 1

9

取你的正则表达式:

 "([^"]*)"(.*$)

当用 编译时.r,这个字符串会产生一个regex对象——如果它匹配它的输入字符串,则必须产生2 个捕获的字符串——一个用于([^"]*),另一个用于(.*$). 你的代码

  case regex(token) => ...

应该反映这一点,所以也许你想要

  case regex(token, otherStuff) => ...

要不就

  case regex(token, _) => ...

为什么?因为case regex(matchedCaputures...)语法有效,因为regex它是一个带有unapplySeq方法的对象。 case regex(token) => ...(大致)翻译为:

 case List(token) => ...

List(token)返回的内容在哪里regex.unapplySeq( inputString )

 regex.unapplySeq("\"test\"") // Returns Some(List("test", ""))

您的正则表达式确实与字符串匹配,"test"但在case语句中,正则表达式提取器的unapplySeq方法返回一个包含2 个字符串的列表,因为这就是正则表达式所说的捕获的内容。这很不幸,但是编译器在这里帮不了你,因为正则表达式是在运行时从字符串编译的。

一种替代方法是使用非捕获组:

 val stringRegex = """"([^"]*)"(?:.*$)"""
 //                             ^^

然后你的代码就可以工作了,因为regex现在将是一个提取器对象,它的 unapplySeq方法只返回一个捕获的组:

 tidyTokens foreach { 
    case regex(token) => println (token + " matches!")
    case t => println ("No match for token " + t)
 }

查看有关Extractor Objects的教程,以更好地了解apply/ unapply /的unapplySeq工作原理。

于 2013-02-27T18:26:04.113 回答