規則表示式與提取器


Scala使用與Java相同的規則表示式(Regular Expression)語法,你可以在 java.util.regex.Pattern  找到語法說明。

以下先介紹幾個簡單的正則表示式。一些常用的範圍,可以使用預先定義的字元類別:
. 符合任一字元
\d 等於 [0-9] 數字
\D 等於 [^0-9] 非數字
\s 等於 [ \t\n\x0B\f\r] 空白字元
\S 等於 [^ \t\n\x0B\f\r] 非空白字元
\w 等於 [a-zA-Z_0-9] 數字或是英文字
\W 等於 [^a-zA-Z_0-9] 非數字與英文字


. 符合任一字元。例如有一字串abcdebcadxbc,使用.bc來比對的話,符合的子字串有abc、ebc、xbc三個;如果使用..cd,則符合的子 字串只有bcd。

以上的例子來根據字元比對,也可以使用「字元類」(Character class)來比較一組字元範圍,例如:
[abc] a、b或c
[^abc] 非a、b、c的其它字元
[a-zA-Z] a到z或A到Z(範圍)
[a-d[m-p]] a到d或m到p(聯集)
[a-z&&[def]] d、e或f(交集)
[a-z&&[^bc]] a到z,除了b與c之外(減集)
[a-z&&[^m-p]] a到z且沒有m到p(a-lq-z)(減集)









可以用Greedy quantifiers來 指定字元可能出現的次數:
X? X出現一次或完全沒有
X* X出現零次或多次
X+ X出現一次或多次
X{n} X出現n次
X{n,} X出現至少n次
X{n,m} X出現至少n次,但不超過m次

字串物件擁有matches()方法可以讓您驗證字串是否符合指定的規則表示式,這通常用於驗證使用者輸入的字串資料是否正確,例如電話號碼格式; replaceAll()方法可以將符合規則表示式的子字串置換為指定的字串;split()方法可以依指定的規則表示式,將符合的子字串分離出來,並以 字串陣列傳回。

在Scala中若要建立可重複使用的規則表示式物件,可使用 scala.util.matching.Regex 類別,例如:
import scala.util.matching.Regex
val yp = new Regex("\\d\\d\\d\\d")

val year = yp.findFirstIn("Birthday: 1975/05/26")
println(year.getOrElse("沒有年份資訊")) // 1975

如果你在"與"間定義規則表示式,那麼對於\d的第一個\字元,你必須避開(Escape),也就是寫為\\d的形式,如果你不想特意作避開字元的動作,則可以在"""與"""定義規則表示式,例如:
import scala.util.matching.Regex
val yp = new Regex("""\d\d\d\d/\d\d/\d\d""")

val year = yp.findFirstIn("Birthday: 1975/05/26")
println(year.getOrElse("沒有年份資訊")) // 1975/05/26

事實上,你可以更簡便地利用 scala.runtime.RichStringr 方法來建立規則表示式:
val yp = """(\d\d\d\d)/(\d\d)/(\d\d)""".r

val year = yp.findFirstIn("Birthday: 1975/05/26")
println(year.getOrElse("沒有年份資訊")) // 1975/05/26

當你使用()將規則表示式中某些規則群組起來時,你可以運用提取器的語法來提取符合的元素,例如:
val Birthday = """(\d\d\d\d)/(\d\d)/(\d\d)""".r
val Birthday(y, m, d) = "1975/05/26"
printf("%s 年 %s 月 %s 日%n", y, m, d) // 1975 年 05 月 26 日

如果()被設定為可出現零次的情況,若要比對的字串沒有出現,則提取出null值,例如:
val Birthday = """(\d\d\d\d)?/?(\d\d)/(\d\d)""".r

val Birthday(y1, m1, d1) = "1975/05/26"
printf("%s 年 %s 月 %s 日%n", y1, m1, d1) // 1975 年 05 月 26 日

val Birthday(y2, m2, d2) = "05/26"
printf("%s 年 %s 月 %s 日%n", y2, m2, d2) // null 年 05 月 26 日

之所以可以使用這樣的提取器語法,是因為 scala.util.matching.Regex 類別定義了unapplySeq()方法,對於符合規則表示式中使用()群組的部份提取出來。