9.10 把正则表达式当做提取器
Scala正则表达式提供了一个买一送一的选择。创建一个正则表达式,就附送一个提取器。Scala的正则表达式就是提取器,所以,很容易就可以在case
表达式里使用。Scala会把每个放在括号里的匹配都展开到一个模式变量里。比如说,"(S|s)cala".r
有一个unapply()
方法,它会返回Option[String]
。另一方面,"(S|s)(cala)".r
的unapply()
会返回Option[String, String]
。用个例子来说明这一点,假定我们想对“GOOG”这只股票进行模式匹配,获取其价格。下面就是用正则表达式实现的方式:
PatternMatching/MatchUsingRegex.scala
def process(input : String) {
val GoogStock = """^GOOG:(\d*\.\d+)""".r
input match {
case GoogStock(price) => println("Price of GOOG is " + price)
case _ => println("not processing " + input)
}
}
process("GOOG:310.84")
process("GOOG:310")
process("IBM:84.01")
这里创建了一个正则表达式匹配字符串,这个字符串以“GOOG:”开头,后面跟着一个正的带小数的十进制数。将其存到一个叫GoogStock
的val
里。幕后,Scala为这个提取器创建了一个unapply()
方法,返回匹配到的括号里模式的值——price
:
Price of GOOG is 310.84
not processing GOOG:310
not processing IBM:84.01
刚刚创建的提取器并不是可重用的。它会寻找股票代码“GOOG”,但如果要找其他股票代码,它就没用了。重用它并不困难。
def process(input : String) {
val MatchStock = """^(.+):(\d*\.\d+)""".r
input match {
case MatchStock("GOOG", price) => println("Price of GOOG is " + price)
case MatchStock("IBM", price) => println("IBM's trading at " + price)
case MatchStock(symbol, price) => printf("Price of %s is %s\n", symbol,
price)
case _ => println("not processing " + input)
}
}
process("GOOG:310.84")
process("IBM:84.01")
process("GE:15.96")
上面的例子里,这个正则表达式匹配一个字符串,这个字符串以任意字符或数字开头,跟着一个冒号,然后是一个正的带小数的十进制数。生成的unapply()
方法会把“:
”前面的部分和后面的部分作为两个单独模式变量返回。这样一来,既可以匹配特定的股票,比如GOOG和IBM,也可以接收传进来的任意股票代码,如上面的case
表达式所示。上面代码的输出如下:
Price of GOOG is 310.84
IBM's trading at 84.01
Price of GE is 15.96
我们看到,Scala在模式匹配里使用正则表达式毫不费力。
在本章里,我们见识到了Scala最强大的特性之一。它现成的功能可以匹配简单的字面量、类型、元组、list等。如果想对匹配有多一点的控制,可以使用case
类,或是无比迷人的提取器。我们见识了如何把正则表达式当作提取器。如果只想匹配简单的字面量,match
就够用了;但如果要匹配任意的模式,Scala提取器就会大开方便之门。接下来,我们会看到Scala如何在并发编程里有效利用这个特性的。