Kotlin 中正規表示式簡介

這篇文章展示瞭如何使用 Regex 類中的大多數函式,使用與 Regex 函式安全相關的 null,以及原始字串如何更容易編寫和讀取正規表示式模式。

RegEx 類

要在 Kotlin 中使用正規表示式,你需要使用 Regex(pattern: String) 類並在該正規表示式物件上呼叫 find(..)replace(..) 等函式。

關於如何使用 Regex 類的示例,如果 input 字串包含 c 或 d,則返回 true:

val regex = Regex(pattern = "c|d")
val matched = regex.containsMatchIn(input = "abc")    // matched: true

理解所有 Regex 函式的基本要素是結果是基於匹配正規表示式 patterninput 字串。某些功能需要完全匹配,而其餘功能僅需要部分匹配。示例中使用的 containsMatchIn(..) 函式需要部分匹配,本文稍後將對此進行說明。

正規表示式的空安全性

find(..)matchEntire(..) 都將返回 MatchResult? 物件。MatchResult 之後的 ? 字元是 Kotlin 安全處理 null所必需的。

這個示例演示了當 find(..) 函式返回 null 時,Kotlin 如何從 Regex 函式安全地處理 null:

val matchResult = 
    Regex("c|d").find("efg")           // matchResult: null
val a = matchResult?.value             // a: null
val b = matchResult?.value.orEmpty()   // b: ""
a?.toUpperCase()                       // Still needs question mark. => null    
b.toUpperCase()                        // Accesses the function directly. => ""

使用 orEmpty() 函式,當你在 b 上呼叫函式時,b 不能為 null,並且不需要 ? 字元。

如果你不關心空值的這種安全處理,Kotlin 允許你使用 !! 字元處理 Java 中的空值:

a!!.toUpperCase()                      // => KotlinNullPointerException

正規表示式中的原始字串

Kotlin 使用原始字串改進了 Java,這使得編寫純正規表示式模式成為可能,而不需要使用 Java 字串所需的雙反斜槓。原始字串用三重引號表示:

"""\d{3}-\d{3}-\d{4}""" // raw Kotlin string
"\\d{3}-\\d{3}-\\d{4}"  // standard Java string

find(輸入:CharSequence,startIndex:Int):MatchResult?

input 字串將與 Regex 物件中的 pattern 匹配。它會返回 Matchresult? 物件,其中第一個匹配的文字位於 startIndex 之後,如果模式與 input 字串不匹配則返回 null。從 MatchResult? 物件的 value 屬性中檢索結果字串。startIndex 引數是可選的,預設值為 0。

要從包含聯絡人詳細資訊的字串中提取第一個有效電話號碼:

val phoneNumber :String? = Regex(pattern = """\d{3}-\d{3}-\d{4}""")
    .find(input = "phone: 123-456-7890, e..")?.value // phoneNumber: 123-456-7890

由於 input 字串中沒有有效的電話號碼,變數 phoneNumber 將為 null

findAll(input:CharSequence,startIndex:Int):Sequence

返回與正規表示式匹配的 input 字串中的所有匹配項。

用字母和數字列印出用空格分隔的所有數字:

val matchedResults = Regex(pattern = """\d+""").findAll(input = "ab12cd34ef")
val result = StringBuilder()
for (matchedText in matchedResults) {
    result.append(matchedText.value + " ")
}

println(result) // => 12 34

matchedResults 變數是一個包含 MatchResult 物件的序列。如果 input 字串沒有數字,findAll(..) 函式將返回一個空序列。

matchEntire(輸入:CharSequence):MatchResult?

如果 input 字串中的所有字元都與正規表示式 pattern 匹配,則將返回等於 input 的字串。否則,null 將被退回。

如果整個輸入字串是數字,則返回輸入字串:

val a = Regex("""\d+""").matchEntire("100")?.value             // a: 100
val b = Regex("""\d+""").matchEntire("100 dollars")?.value     // b: null

matches(輸入:CharSequence):Boolean

如果整個輸入字串與正規表示式模式匹配,則返回 true。否則就錯了。

測試兩個字串是否只包含數字:

val regex = Regex(pattern = """\d+""")
regex.matches(input = "50")             // => true
regex.matches(input = "50 dollars")     // => false

containsMatchIn(input:CharSequence):Boolean

如果輸入字串的一部分與正規表示式模式匹配,則返回 true。否則就錯了。

測試兩個字串是否包含至少一個數字:

Regex("""\d+""").containsMatchIn("50 dollars")       // => true
Regex("""\d+""").containsMatchIn("Fifty dollars")    // => false

split(輸入:CharSequence,limit:Int):List

返回沒有所有正規表示式匹配的新列表。

要返回沒有數字的列表:

val a = Regex("""\d+""").split("ab12cd34ef")     // a: [ab, cd, ef]
val b = Regex("""\d+""").split("This is a test") // b: [This is a test]

列表中有一個元素用於每個拆分。第一個 input 字串有三個數字。這導致列表包含三個元素。

replace(輸入:CharSequence,replacement:String):String

用替換字串替換 input 字串中正規表示式 pattern 的所有匹配項。

要用 x 替換字串中的所有數字:

val result = Regex("""\d+""").replace("ab12cd34ef", "x") // result: abxcdxef