Scala基础教程(八):模式匹配、正则表达式
匹配使用case 類:
case classes是用于模式匹配與case 表達(dá)式指定類。這些都是標(biāo)準(zhǔn)類具有特殊修飾:case。下面是一個(gè)簡(jiǎn)單的模式使用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) }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Hi Alice! Hi Bob! Age: 32 year, name: Charlie? ? C:/>增加 case 關(guān)鍵字使編譯器自動(dòng)添加了許多實(shí)用的功能。關(guān)鍵字建議與模式匹配的情況下表達(dá)式的關(guān)聯(lián)。
首先,編譯器會(huì)自動(dòng)轉(zhuǎn)換的構(gòu)造函數(shù)的參數(shù)為不可變的字段(vals)。val關(guān)鍵字是可選的。如果想可變字段,使用var關(guān)鍵字。因此,構(gòu)造函數(shù)的參數(shù)列表現(xiàn)在更短。
其次,編譯器自動(dòng)實(shí)現(xiàn)equals, hashCode, 和toString方法的類,它使用指定為構(gòu)造函數(shù)參數(shù)的字段。因此,不再需要自己的toString方法。
最后,還消失Person類的主體部分,因?yàn)闆]有需要定義的方法!
?
?
?
Scala支持通過Regex類的scala.util.matching封裝正則表達(dá)式。讓我們看看一個(gè)例子,我們將嘗試從Scala中一個(gè)語句中找出單詞:
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) ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Some(Scala) ? C:/>我們創(chuàng)建一個(gè)字符串,并調(diào)用r()方法就可以了。Scala中字符串隱式轉(zhuǎn)換為一個(gè)RichString并調(diào)用該方法來獲得正則表達(dá)式的一個(gè)實(shí)例。找到第 一個(gè)正則表達(dá)式匹配,只需調(diào)用findFirstIn()方法。而非只找到第一次出現(xiàn)。如果想找到匹配的單詞的所有事件,可以使用findAllIn() 方法,并在情況下,有目標(biāo)字符串中使用多個(gè)Scala的單詞,這將返回所有匹配的集合單詞。
可以使用mkString()方法來連接所產(chǎn)生的服務(wù),可以使用管道(|)搜索Scala中小型和資本的情況下,使用正則表達(dá)式構(gòu)造來代替或r()方法創(chuàng)建一個(gè)模式如下:
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(",")) ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Scala,scala ? C:/>如果想更換匹配的文本,可以使用replaceFirstIn()以取代第一個(gè)匹配項(xiàng)或replaceAllIn(),以取代所有出現(xiàn)如下:
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")) ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Java is scalable and cool ? C:/>形成正則表達(dá)式:
Scala繼承了Java,這反過來又繼承了大部分的Perl的功能,它的正則表達(dá)式語法。這里只是一些例子,應(yīng)該是足夠的說明:
下面是表,列出了所有的正則表達(dá)式元字符的語法可用在Java中:
| 子表達(dá)式 | 匹配 |
| ^ | 匹配行頭? |
| $ | 匹配行尾 |
| . | 匹配除換行符任何單個(gè)字符。用m選項(xiàng)也允許使之匹配換行符。 |
| [...] | 匹配括號(hào)內(nèi)任何單個(gè)字符。 |
| [^...] | 匹配任何單個(gè)字符不是在括號(hào)中 |
| \A | 整個(gè)字符串的開始 |
| \z | 整個(gè)字符串結(jié)束 |
| \Z | 最終,除了允許的最后行結(jié)束整個(gè)字符串。 |
| re* | 匹配0或多次出現(xiàn)前面表達(dá)式。 |
| re+ | 匹配1個(gè)或多個(gè)的先前東西 |
| re? | 匹配0或1發(fā)生前表達(dá)式。 |
| re{ n} | 精確匹配n個(gè)前面表達(dá)式的數(shù)量。 |
| re{ n,} | 匹配n或多次出現(xiàn)前面的表達(dá)。 |
| re{ n, m} | 至少匹配n和在前面的表現(xiàn)最為m次出現(xiàn)。 |
| a|b | 匹配a或b。 |
| (re) | 組正則表達(dá)式并記住匹配的文本。 |
| (?: re) | 組正則表達(dá)式而不記住匹配的文本。 |
| (?> re) | 匹配獨(dú)立模式而不反向追蹤。 |
| \w | 匹配單詞字符。 |
| \W | 匹配非單詞字符。 |
| \s | 匹配空白。相當(dāng)于 [ f]. |
| \S | 匹配非空白。 |
| \d | 匹配數(shù)字。相當(dāng)于 [0-9]. |
| \D | 匹配非數(shù)字。 |
| \A | 匹配開始的字符串。 |
| \Z | 匹配字符串的結(jié)尾。如果一個(gè)換行符存在,它只是換行之前匹配。 |
| \z | 匹配字符串的結(jié)尾。 |
| \G | 匹配點(diǎn),最后一次匹配結(jié)束。 |
| \n | 反向引用以捕獲組編號(hào) "n" |
| \b | 匹配單詞邊界之外時(shí),括號(hào)內(nèi)。匹配退格(0×08)括號(hào)里面。 |
| \B | 匹配非單詞邊界。 |
| \n, \t, etc. | 匹配換行符,回車,制表符等 |
| \Q | 轉(zhuǎn)義(引用)所有字符為?\E |
| \E | 尾部引用開始 \Q |
正則表達(dá)式的例子:
| 示例 | 描述 |
| . | 匹配除了換行符的任何字符 |
| [Rr]uby | 匹配?"Ruby" 或"ruby" |
| rub[ye] | 匹配"ruby" 或?"rube" |
| [aeiou] | 匹配任何一個(gè)小寫元音 |
| [0-9] | 匹配任何數(shù)字;同 [0123456789] |
| [a-z] | 匹配任意小寫ASCII字母 |
| [A-Z] | 匹配任意大寫ASCII字母 |
| [a-zA-Z0-9] | 匹配任何上述 |
| [^aeiou] | 匹配元音以外的任何一個(gè)小寫字符 |
| [^0-9] | 匹配數(shù)字以外的任何其他 |
| \d | 匹配一個(gè)數(shù)字: [0-9] |
| \D | 匹配一個(gè)非數(shù)字: [^0-9] |
| \s | 匹配一個(gè)空白字符: [ f] |
| \S | 匹配非空白: [^ f] |
| \w | 匹配一個(gè)字符: [A-Za-z0-9_] |
| \W | 匹配一個(gè)非單詞字符: [^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 個(gè)數(shù)字 |
| \d{3,} | 匹配 3 個(gè)或多個(gè)數(shù)字 |
| \d{3,5} | 匹配3, 4, 或5 個(gè)數(shù)字 |
| \D\d+ | 不分組: + repeats \d |
| (\D\d)+/ | 分組: + repeats \Dd 對(duì) |
| ([Rr]uby(, )?)+ | 匹配 "Ruby", "Ruby, ruby, ruby", 等. |
需要注意的是每一個(gè)反斜杠上述字符串中出現(xiàn)兩次。這是因?yàn)樵贘ava和Scala一個(gè)反斜杠是一個(gè)轉(zhuǎn)義字符的字符串,而不是一個(gè)普通字符顯示出來的字符串。所以不是.. 需要寫.\ 。得到的字符串中的一個(gè)反斜杠。請(qǐng)查看下面的例子:
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(",")) ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test able1 ? C:/>?
?
Scala的異常的工作像許多其他語言,如Java異常。而不是正常方式返回的值,方法可以通過拋出一個(gè)異常終止。然而,Scala實(shí)際上并沒有檢查異常。
當(dāng)要處理異常,那么可使用try{...}catch{...} 塊,就像在Java中除了catch塊采用匹配識(shí)別和處理異常。
拋出異常:
拋出一個(gè)異常看起來類似于Java。創(chuàng)建一個(gè)異常對(duì)象,然后使用throw關(guān)鍵字把它拋出:
throw new IllegalArgumentException捕獲異常:
Scala中try/catch在一個(gè)單獨(dú)的塊捕捉任何異常,然后使用case塊進(jìn)行模式匹配,如下圖所示:
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") ???????? } ????? } ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Missing file exception ? C:/>這種try-catch表達(dá)的行為在其他語言處理異常是一樣的。body是執(zhí)行體,如果它拋出一個(gè)異常,每個(gè)catch子句都依次嘗試捕獲。
finally子句:
如果想知道引起一些代碼是如何表達(dá)的終止執(zhí)行,可以用一個(gè)finally子句包住一個(gè)表達(dá)式,finally塊什么時(shí)候都會(huì)執(zhí)行。
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...") ????? } ?? } }當(dāng)上述代碼被編譯和執(zhí)行時(shí),它產(chǎn)生了以下結(jié)果:
C:/>scalac Test.scala C:/>scala Test Missing file exception Exiting finally... ? C:/>?
?
提取器在Scala中是一個(gè)對(duì)象,有一個(gè)叫非應(yīng)用作為其成員的一種方法。即不應(yīng)用方法的目的是要匹配的值,并把它拆開。通常,提取對(duì)象還限定了雙方法申請(qǐng)構(gòu)建值,但是這不是必需的。
下面的例子顯示電子郵件地址的提取器對(duì)象:
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 ????? } ?? } }這個(gè)對(duì)象定義了 apply 和unapply 方法。該apply 方法具有相同的含義:它原來的測(cè)試為可以被應(yīng)用到的參數(shù)在括號(hào)中的方法所應(yīng)用的相同的方式的對(duì)象。所以,可以寫為Test("Zara", "gmail.com") 來構(gòu)造字符串“Zara@gmail.com”。
unapply方法使測(cè)試類成為一個(gè)提取器并反轉(zhuǎn)應(yīng)用的構(gòu)造過程。應(yīng)用需要兩個(gè)字符串,并形成了一個(gè)電子郵件地址以找到它們,非應(yīng)用unapply需要一個(gè)電子郵件地址,并可能返回兩個(gè)字符串:用戶和地址的域名。
unapply還必須處理中給定的字符串不是一個(gè)電子郵件地址的情況。這就是為什么unapply返回一個(gè)選項(xiàng)型過對(duì)字符串。其結(jié)果要么是一些(用戶域) 如果字符串str使用給定電子郵件地址的用戶和域的部分,或None,如果str不是一個(gè)電子郵件地址。下面是一些例子:
unapply("Zara@gmail.com") equals Some("Zara", "gmail.com") unapply("Zara Ali") equals None讓我們編譯和運(yùn)行上面的程序,這將產(chǎn)生以下結(jié)果:
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
總結(jié)
以上是生活随笔為你收集整理的Scala基础教程(八):模式匹配、正则表达式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala基础教程(七):类和对象、特征
- 下一篇: Scala基础教程(九):提取器、文件I