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