Scala基础教程(八):模式匹配、正则表达式

匹配使用case 类:

case classes是用于模式匹配与case 表达式指定类。这些都是标准类具有特殊修饰:case。下面是一个简单的模式使用case class匹配示例:

object Test {
   def main(args: Array[String]) {
          val alice = new Person("Alice", 25)
             val bob = new Person("Bob", 32)
          val charlie = new Person("Charlie", 32)
   
      for (person <- List(alice, bob, charlie)) {
         person match {
            case Person("Alice", 25) => println("Hi Alice!")
            case Person("Bob", 32) => println("Hi Bob!")
            case Person(name, age) =>
               println("Age: " + age + " year, name: " + name + "?")
         }
      }
   }
   // case class, empty one.
   case class Person(name: String, age: Int)
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Hi Alice!
Hi Bob!
Age: 32 year, name: Charlie?
 
C:/>

增加 case 关键字使编译器自动添加了许多实用的功能。关键字建议与模式匹配的情况下表达式的关联。

首先,编译器会自动转换的构造函数的参数为不可变的字段(vals)。val关键字是可选的。如果想可变字段,使用var关键字。因此,构造函数的参数列表现在更短。

其次,编译器自动实现equals, hashCode, 和toString方法的类,它使用指定为构造函数参数的字段。因此,不再需要自己的toString方法。

最后,还消失Person类的主体部分,因为没有需要定义的方法!

 

 

 

Scala支持通过Regex类的scala.util.matching封装正则表达式。让我们看看一个例子,我们将尝试从Scala中一个语句中找出单词:

import scala.util.matching.Regex
 
object Test {
   def main(args: Array[String]) {
      val pattern = "Scala".r
      val str = "Scala is Scalable and cool"
      
      println(pattern findFirstIn str)
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Some(Scala)
 
C:/>

我们创建一个字符串,并调用r()方法就可以了。Scala中字符串隐式转换为一个RichString并调用该方法来获得正则表达式的一个实例。找到第 一个正则表达式匹配,只需调用findFirstIn()方法。而非只找到第一次出现。如果想找到匹配的单词的所有事件,可以使用findAllIn() 方法,并在情况下,有目标字符串中使用多个Scala的单词,这将返回所有匹配的集合单词。

可以使用mkString()方法来连接所产生的服务,可以使用管道(|)搜索Scala中小型和资本的情况下,使用正则表达式构造来代替或r()方法创建一个模式如下:

import scala.util.matching.Regex
 
object Test {
   def main(args: Array[String]) {
      val pattern = new Regex("(S|s)cala")
      val str = "Scala is scalable and cool"
      
      println((pattern findAllIn str).mkString(","))
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Scala,scala
 
C:/>

如果想更换匹配的文本,可以使用replaceFirstIn()以取代第一个匹配项或replaceAllIn(),以取代所有出现如下:

object Test {
   def main(args: Array[String]) {
      val pattern = "(S|s)cala".r
      val str = "Scala is scalable and cool"
      
      println(pattern replaceFirstIn(str, "Java"))
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Java is scalable and cool
 
C:/>

形成正则表达式:

Scala继承了Java,这反过来又继承了大部分的Perl的功能,它的正则表达式语法。这里只是一些例子,应该是足够的说明:

下面是表,列出了所有的正则表达式元字符的语法可用在Java中:

子表达式

匹配

^

匹配行头 

$

匹配行尾

.

匹配除换行符任何单个字符。用m选项也允许使之匹配换行符。

[...]

匹配括号内任何单个字符。

[^...]

匹配任何单个字符不是在括号中

\A

整个字符串的开始

\z

整个字符串结束

\Z

最终,除了允许的最后行结束整个字符串。

re*

匹配0或多次出现前面表达式。

re+

匹配1个或多个的先前东西

re?

匹配01发生前表达式。

re{ n}

精确匹配n个前面表达式的数量。

re{ n,}

匹配n或多次出现前面的表达。

re{ n, m}

至少匹配n和在前面的表现最为m次出现。

a|b

匹配ab

(re)

组正则表达式并记住匹配的文本。

(?: re)

组正则表达式而不记住匹配的文本。

(?> re)

匹配独立模式而不反向追踪。

\w

匹配单词字符。

\W

匹配非单词字符。

\s

匹配空白。相当于 [ f].

\S

匹配非空白。

\d

匹配数字。相当于 [0-9].

\D

匹配非数字。

\A

匹配开始的字符串。

\Z

匹配字符串的结尾。如果一个换行符存在,它只是换行之前匹配。

\z

匹配字符串的结尾。

\G

匹配点,最后一次匹配结束。

\n

反向引用以捕获组编号 "n"

\b

匹配单词边界之外时,括号内。匹配退格(0×08)括号里面。

\B

匹配非单词边界。

\n, \t, etc.

匹配换行符,回车,制表符等

\Q

转义(引用)所有字符为 \E

\E

尾部引用开始 \Q

正则表达式的例子:

示例

描述

.

匹配除了换行符的任何字符

[Rr]uby

匹配 "Ruby" "ruby"

rub[ye]

匹配"ruby"  "rube"

[aeiou]

匹配任何一个小写元音

[0-9]

匹配任何数字; [0123456789]

[a-z]

匹配任意小写ASCII字母

[A-Z]

匹配任意大写ASCII字母

[a-zA-Z0-9]

匹配任何上述

[^aeiou]

匹配元音以外的任何一个小写字符

[^0-9]

匹配数字以外的任何其他

\d

匹配一个数字: [0-9]

\D

匹配一个非数字: [^0-9]

\s

匹配一个空白字符: [ f]

\S

匹配非空白: [^ f]

\w

匹配一个字符: [A-Za-z0-9_]

\W

匹配一个非单词字符: [^A-Za-z0-9_]

ruby?

匹配 "rub" or "ruby": the y is optional

ruby*

匹配 "rub" plus 0 or more ys

ruby+

匹配 "rub" plus 1 or more ys

\d{3}

匹配只有 3 个数字

\d{3,}

匹配 3 个或多个数字

\d{3,5}

匹配3, 4, 5 个数字

\D\d+

不分组: + repeats \d

(\D\d)+/

分组: + repeats \Dd

([Rr]uby(, )?)+

匹配 "Ruby", "Ruby, ruby, ruby", .

需要注意的是每一个反斜杠上述字符串中出现两次。这是因为在Java和Scala一个反斜杠是一个转义字符的字符串,而不是一个普通字符显示出来的字符串。所以不是.. 需要写.\ 。得到的字符串中的一个反斜杠。请查看下面的例子:

import scala.util.matching.Regex
 
object Test {
   def main(args: Array[String]) {
      val pattern = new Regex("abl[ae]\d+")
      val str = "ablaw is able1 and cool"
      
      println((pattern findAllIn str).mkString(","))
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
able1
 
C:/>

 

 

Scala的异常的工作像许多其他语言,如Java异常。而不是正常方式返回的值,方法可以通过抛出一个异常终止。然而,Scala实际上并没有检查异常。

当要处理异常,那么可使用try{...}catch{...} 块,就像在Java中除了catch块采用匹配识别和处理异常。

抛出异常:

抛出一个异常看起来类似于Java。创建一个异常对象,然后使用throw关键字把它抛出:

throw new IllegalArgumentException

捕获异常:

Scala中try/catch在一个单独的块捕捉任何异常,然后使用case块进行模式匹配,如下图所示:

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
 
object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException =>{
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      }
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Missing file exception
 
C:/>

这种try-catch表达的行为在其他语言处理异常是一样的。body是执行体,如果它抛出一个异常,每个catch子句都依次尝试捕获。

finally子句:

如果想知道引起一些代码是如何表达的终止执行,可以用一个finally子句包住一个表达式,finally块什么时候都会执行。

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
 
object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException => {
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      } finally {
         println("Exiting finally...")
      }
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Missing file exception
Exiting finally...
 
C:/>

 

 

提取器在Scala中是一个对象,有一个叫非应用作为其成员的一种方法。即不应用方法的目的是要匹配的值,并把它拆开。通常,提取对象还限定了双方法申请构建值,但是这不是必需的。

下面的例子显示电子邮件地址的提取器对象:

object Test {
   def main(args: Array[String]) {
      
      println ("Apply method : " + apply("Zara", "gmail.com"));
      println ("Unapply method : " + unapply("Zara@gmail.com"));
      println ("Unapply method : " + unapply("Zara Ali"));
 
   }
   // The injection method (optional)
   def apply(user: String, domain: String) = {
      user +"@"+ domain
   }
 
   // The extraction method (mandatory)
   def unapply(str: String): Option[(String, String)] = {
      val parts = str split "@"
      if (parts.length == 2){
         Some(parts(0), parts(1)) 
      }else{
         None
      }
   }
}

这个对象定义了 apply 和unapply 方法。该apply 方法具有相同的含义:它原来的测试为可以被应用到的参数在括号中的方法所应用的相同的方式的对象。所以,可以写为Test("Zara", "gmail.com") 来构造字符串“Zara@gmail.com”。

unapply方法使测试类成为一个提取器并反转应用的构造过程。应用需要两个字符串,并形成了一个电子邮件地址以找到它们,非应用unapply需要一个电子邮件地址,并可能返回两个字符串:用户和地址的域名。

unapply还必须处理中给定的字符串不是一个电子邮件地址的情况。这就是为什么unapply返回一个选项型过对字符串。其结果要么是一些(用户域) 如果字符串str使用给定电子邮件地址的用户和域的部分,或None,如果str不是一个电子邮件地址。下面是一些例子:

unapply("Zara@gmail.com") equals Some("Zara", "gmail.com")
unapply("Zara Ali") equals None

让我们编译和运行上面的程序,这将产生以下结果:

C:/>scalac Test.scala
C:/>scala Test
Apply method : Zara@gmail.com
Unapply method : Some((Zara,gmail.com))
Unapply method : None
 
C:/>


from: http://www.yiibai.com/scala/scala_basic_syntax.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值