一、正则表达式:定义、作用、应用场景
- 定义正则表达式(Regular Expression)是一种用于匹配、查找、替换字符串的字符模式规则,通过预定义的符号和语法组合,描述字符串的结构特征。
- 作用
- 字符串匹配:验证字符串是否符合特定格式(如手机号、邮箱);
- 字符串查找:提取文本中符合规则的子串(如日志中的时间);
- 字符串替换:批量修改文本中符合规则的内容(如替换敏感词)。
- 应用场景
- 数据验证:手机号、邮箱、身份证号等格式校验;
- 文本解析:日志分析、爬虫数据提取;
- 内容处理:代码注释清理、敏感词过滤;
- 数据格式化:日期、数字的统一格式转换。
二、正则表达式的组成部分
正则表达式由普通字符和元字符组成:
-
普通字符:无特殊含义的字符(如字母、数字、空格),直接匹配自身(如
abc匹配字符串中的 “abc”)。 -
元字符:具有特殊含义的字符,是正则的核心,常见类型:
- 匹配位置:
^(行开头)、$(行结尾); - 匹配数量:
*(0 次或多次)、+(1 次或多次)、?(0 次或 1 次)、{n}(恰好 n 次); - 匹配范围:
[](字符集)、[^](非字符集)、|(或); - 预定义字符:
\d(数字)、\w(字母 / 数字 / 下划线)、\s(空白符)等。
- 匹配位置:
三、正则表达式的核心规则
-
匹配位置
^abc:匹配以 “abc” 开头的字符串;abc$:匹配以 “abc” 结尾的字符串;^abc$:精确匹配 “abc”(仅该字符串)。
-
匹配数量
a*:匹配 0 个或多个 “a”;a+:匹配 1 个或多个 “a”;a?:匹配 0 个或 1 个 “a”;a{3}:匹配恰好 3 个 “a”;a{2,5}:匹配 2 到 5 个 “a”;a{2,}:匹配至少 2 个 “a”。
-
匹配范围
[a-z]:匹配任意小写字母;[0-9]:匹配任意数字(等价于\d);[^0-9]:匹配非数字字符;a|b:匹配 “a” 或 “b”。
-
预定义字符(简化写法)
\d:等价于[0-9](数字);\w:等价于[a-zA-Z0-9_](单词字符);\s:等价于[ \t\n\r](空白符);.:匹配任意字符(除换行符)。
四、Scala 中正则表达式的应用案例
Scala 通过scala.util.matching.Regex类实现正则操作,以下是常见场景示例:
案例 1:数据格式验证(手机号)
scala
import scala.util.matching.Regex
// 定义手机号正则:1开头,第二位为3-9,后9位为数字
val phoneRegex: Regex = "^1[3-9]\d{9}$".r
def validatePhone(phone: String): Boolean = phoneRegex.matches(phone)
// 测试
println(validatePhone("13812345678")) // true
println(validatePhone("12812345678")) // false(第二位不符合)
案例 2:提取文本中的邮箱
scala
val emailRegex: Regex = "\w+@\w+\.\w+".r
val text = "我的邮箱是test@example.com,备用邮箱是abc123@xyz.cn"
// 提取所有匹配的邮箱
val emails = emailRegex.findAllIn(text).toList
println(emails) // List(test@example.com, abc123@xyz.cn)
案例 3:替换文本中的敏感词
scala
val sensitiveRegex: Regex = "敏感词1|敏感词2".r
val content = "这是敏感词1,那是敏感词2"
// 将敏感词替换为“***”
val filteredContent = sensitiveRegex.replaceAllIn(content, "***")
println(filteredContent) // 这是***,那是***
案例 4:解析日志中的时间
scala
// 日志格式示例:2025-12-22 14:30:00 [INFO] 操作成功
val logTimeRegex: Regex = "(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})".r
val log = "2025-12-22 14:30:00 [INFO] 操作成功"
logTimeRegex.findFirstIn(log) match {
case Some(time) => println(s"日志时间:$time") // 日志时间:2025-12-22 14:30:00
case None => println("未匹配到时间")
}
模板:
模板说明
- 所有模板基于
scala.util.matching.Regex实现; - 关键参数已标注注释,替换正则规则 / 目标文本即可适配业务场景;
- 包含异常处理(如无匹配时的兜底逻辑),保证代码健壮性。
scala
import scala.util.matching.Regex
/**
* Scala 正则表达式通用操作模板
* 涵盖:格式验证、全量提取、单值提取、分组提取、批量替换、单次替换
*/
object RegexTemplate {
// ====================== 1. 格式验证模板(如手机号/邮箱/身份证) ======================
/**
* 验证字符串是否符合指定正则规则
* @param regexStr 正则表达式
* @param target 待验证字符串
* @return 验证结果(true/false)
*/
def validateFormat(regexStr: String, target: String): Boolean = {
val regex: Regex = regexStr.r
regex.pattern.matcher(target).matches() // 精准匹配(全字符串符合规则)
}
// ====================== 2. 全量提取模板(提取所有匹配的子串) ======================
/**
* 提取文本中所有符合正则规则的子串
* @param regexStr 正则表达式
* @param text 目标文本
* @return 匹配结果列表(无匹配则返回空列表)
*/
def extractAll(regexStr: String, text: String): List[String] = {
val regex: Regex = regexStr.r
regex.findAllIn(text).toList // 惰性迭代器转列表,无匹配则为空
}
// ====================== 3. 单值提取模板(提取第一个匹配的子串) ======================
/**
* 提取文本中第一个符合正则规则的子串
* @param regexStr 正则表达式
* @param text 目标文本
* @return 第一个匹配结果(Option类型,避免空指针)
*/
def extractFirst(regexStr: String, text: String): Option[String] = {
val regex: Regex = regexStr.r
regex.findFirstIn(text)
}
// ====================== 4. 分组提取模板(提取正则分组中的内容) ======================
/**
* 提取正则分组中的内容(如从日志中拆分时间、级别、内容)
* @param regexStr 带分组的正则表达式(分组用()包裹)
* @param text 目标文本
* @return 分组结果(List[List[String]],外层是匹配项,内层是分组)
*/
def extractGroups(regexStr: String, text: String): List[List[String]] = {
val regex: Regex = regexStr.r
regex.findAllMatchIn(text)
.map(matchResult => (0 to matchResult.groupCount).map(matchResult.group).toList)
.toList
}
// ====================== 5. 批量替换模板(替换所有匹配的子串) ======================
/**
* 批量替换文本中所有符合正则规则的子串
* @param regexStr 正则表达式
* @param text 目标文本
* @param replacement 替换后的内容
* @return 替换后的文本
*/
def replaceAll(regexStr: String, text: String, replacement: String): String = {
val regex: Regex = regexStr.r
regex.replaceAllIn(text, replacement)
}
// ====================== 6. 单次替换模板(替换第一个匹配的子串) ======================
/**
* 替换文本中第一个符合正则规则的子串
* @param regexStr 正则表达式
* @param text 目标文本
* @param replacement 替换后的内容
* @return 替换后的文本
*/
def replaceFirst(regexStr: String, text: String, replacement: String): String = {
val regex: Regex = regexStr.r
regex.replaceFirstIn(text, replacement)
}
// ====================== 模板使用示例 ======================
def main(args: Array[String]): Unit = {
// 示例1:验证手机号
val phoneRegex = "^1[3-9]\d{9}$"
println("手机号验证(13812345678):" + validateFormat(phoneRegex, "13812345678")) // true
println("手机号验证(12812345678):" + validateFormat(phoneRegex, "12812345678")) // false
// 示例2:提取所有邮箱
val emailRegex = "\w+@\w+\.\w+"
val text = "邮箱1:test@example.com,邮箱2:abc123@xyz.cn"
println("提取所有邮箱:" + extractAll(emailRegex, text)) // List(test@example.com, abc123@xyz.cn)
// 示例3:提取第一个匹配的数字
val numRegex = "\d+"
val content = "年龄:25,身高:180cm"
extractFirst(numRegex, content).foreach(firstNum => println("第一个数字:" + firstNum)) // 25
// 示例4:分组提取日志(时间、级别、内容)
val logRegex = "(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w+)\] (.*)"
val log = "2025-12-22 15:30:00 [INFO] 操作成功;2025-12-22 15:31:00 [ERROR] 连接失败"
println("日志分组提取:")
extractGroups(logRegex, log).foreach(group => println(group))
// 输出:
// List(2025-12-22 15:30:00 [INFO] 操作成功, 2025-12-22 15:30:00, INFO, 操作成功)
// List(2025-12-22 15:31:00 [ERROR] 连接失败, 2025-12-22 15:31:00, ERROR, 连接失败)
// 示例5:替换所有敏感词
val sensitiveRegex = "敏感词1|敏感词2"
val sensitiveText = "这是敏感词1,那是敏感词2"
println("敏感词替换后:" + replaceAll(sensitiveRegex, sensitiveText, "***")) // 这是***,那是***
// 示例6:替换第一个数字为99
println("替换第一个数字:" + replaceFirst(numRegex, content, "99")) // 年龄:99,身高:180cm
}
}
模板扩展说明
- 正则转义处理:Scala 字符串中 `` 需转义为
\(如\d写为\d),若正则规则复杂,可使用原始字符串raw"^1[3-9]\d{9}$"避免多次转义; - 分组索引:
matchResult.group(0)是整个匹配串,group(1)/group(2)对应正则中第 1/2 个括号分组; - 性能优化:若同一正则需多次使用,建议提前编译为
Regex实例(避免重复编译); - 复杂匹配:可结合
Regex.Match的start/end方法获取匹配子串的位置,实现更精细的文本处理。