(一)matches方法:全量验证字符串合法性
1. 方法核心介绍
正则表达式对象的 matches 方法,核心作用是验证给定的字符串是否完全满足正则表达式的匹配要求(即字符串从头到尾必须完整匹配正则规则,不能有多余字符),返回值为布尔类型(Boolean,true 表示符合规则,false 表示不符合规则),是数据格式校验的核心方法。
其标准使用格式如下:
// 格式:val 验证结果 = 正则表达式对象.matches(目标字符串)
val 结果: Boolean = reg.matches(目标字符串)
2. 基础示例(可直接运行)
import scala.util.matching.Regex
object RegexMatchesDemo {
def main(args: Array[String]): Unit = {
// 定义正则规则:匹配恰好3位数字
val numReg: Regex = "\d{3}".r
// 验证符合规则的字符串
val validResult1 = numReg.matches("123")
println("字符串"123"是否符合3位数字规则:" + validResult1) // 输出 true
// 验证不符合规则的字符串(包含非数字字符)
val invalidResult1 = numReg.matches("12a")
println("字符串"12a"是否符合3位数字规则:" + invalidResult1) // 输出 false
// 验证不符合规则的字符串(长度不足3位)
val invalidResult2 = numReg.matches("12")
println("字符串"12"是否符合3位数字规则:" + invalidResult2) // 输出 false
// 验证不符合规则的字符串(长度超过3位)
val invalidResult3 = numReg.matches("1234")
println("字符串"1234"是否符合3位数字规则:" + invalidResult3) // 输出 false
}
}
(二)实战案例:验证合法用户名
1. 需求背景
在论坛、电商平台、管理系统等用户注册场景中,为了保证用户名的规范性和可识别性,需要对用户输入的用户名进行格式校验,避免无效或不规范的用户名注册。
2. 合法用户名规则
| **规则编号 | 规则详情 |
|---|---|
| 规则 1 | 字符构成合法:仅允许包含大小写英文字母(a-z、A-Z)、数字(0-9)以及下划线(_) |
| 规则 2 | 长度合规:用户名总长度限定在 6 到 12 位之间(既避免过短易重复,也避免过长不易记忆) |
| 规则 3 | 开头合规:不能以数字开头(防止用户名与纯数字 ID 混淆,提升辨识度) |
3. 正则表达式编写与解读
(1)最终正则规则
^[a-zA-Z][a-zA-Z0-9_]{5,11}$
2)规则详细解读
| 正则片段 | 片段解读 |
|---|---|
^ | 行首锚点,限定匹配从字符串的开头开始(确保用户名开头无多余字符) |
[a-zA-Z] | 用户名首字符:仅匹配大小写英文字母中的任意一个,满足 “不能以数字开头” 的规则 |
[a-zA-Z0-9_] | 用户名后续字符:匹配大小写英文字母、数字、下划线中的任意一个,满足 “字符构成合法” 的规则 |
{5,11} | 量词限定:表示前面的字符集需要出现 5 到 11 次。结合首字符的 1 位,总长度为 6(1+5)到 12(1+11)位,满足 “长度合规” 的规则 |
$ | 行尾锚点,限定匹配到字符串的结尾结束(确保用户名结尾无多余字符) |
4. 完整可运行代码(交互式校验)
object UsernameRegexValidationDemo {
def main(args: Array[String]): Unit = {
// 定义匹配合法用户名的正则表达式(严格遵循3条规则)
val validUsernameReg = "^[a-zA-Z][a-zA-Z0-9_]{5,11}$".r
// 标记程序是否持续运行
var isRunning = true
println("=== 用户名合法性校验工具 ===")
println("规则:1. 6-12位长度;2. 以大小写字母开头;3. 仅包含字母、数字、下划线")
println("输入任意内容进行校验,输入"exit"退出程序\n")
// 循环接收用户输入,实现交互式校验
while (isRunning) {
print("请输入你要验证的用户名:")
val userName = readLine().trim // 获取用户输入并去除首尾空格
// 退出程序判断
if (userName.equalsIgnoreCase("exit")) {
isRunning = false
println("程序已退出!")
} else {
// 调用matches方法进行合法性校验
val isLegal = validUsernameReg.matches(userName)
// 根据校验结果输出提示信息
if (isLegal) {
println(s"✅ 用户名"$userName"符合要求,可以注册!")
} else {
println(s"❌ 用户名"$userName"不符合要求,请重新输入!")
}
}
}
}
}
5. 测试用例参考
| 用户名 | 校验结果 | 原因分析 |
|---|---|---|
User_123 | 合法(true) | 以大写字母 U 开头,长度 8 位,仅包含字母、数字、下划线 |
user123456 | 合法(true) | 以小写字母 u 开头,长度 10 位,仅包含字母、数字 |
123User | 不合法(false) | 以数字 1 开头,违反规则 3 |
User_ | 不合法(false) | 长度仅 5 位,违反规则 2 |
User123456789 | 不合法(false) | 长度 13 位,违反规则 2 |
User@123 | 不合法(false) | 包含特殊字符 @,违反规则 1 |
(三)replaceAllIn方法:正则批量替换文本
1. 方法核心介绍
replaceAllIn 是 Scala 正则表达式的核心替换方法,功能是在目标字符串中,查找所有匹配正则规则的子串,并将其替换为指定内容,最终返回替换后的全新字符串(原字符串不会被修改,Scala 字符串为不可变类型)。
其核心使用格式有两种:
(1)简单替换(固定内容替换)
格式:val 替换后字符串 = 正则表达式对象.replaceAllIn(目标字符串, 固定替换内容)
val newStr: String = reg.replaceAllIn(targetStr, replaceStr)
(2)灵活替换(基于匹配结果动态替换)
/ 格式:val 替换后字符串 = 正则表达式对象.replaceAllIn(目标字符串, 匹配结果 => 动态替换逻辑)
val newStr: String = reg.replaceAllIn(targetStr, m => 自定义替换逻辑)
. 基础示例(固定内容替换)
需求:将目标字符串中所有的小写字母bc(连续)替换为01
object RegexReplaceBasicDemo {
def main(args: Array[String]): Unit = {
// 1. 定义正则规则:匹配连续的小写字母bc
val bcReg = "bc".r
// 2. 定义目标字符串
val targetStr = "abcdabcdbcbc"
// 3. 调用replaceAllIn方法进行固定替换
val newStr = bcReg.replaceAllIn(targetStr, "01")
// 4. 输出结果
println(s"原字符串:$targetStr")
println(s"替换后字符串:$newStr")
// 输出结果:a01da01d0101
}
}
(四)实战案例:手机号中间 4 位打马赛克
1. 需求任务
在实际业务中(如用户信息展示、日志脱敏等场景),为了保护用户隐私,需要将手机号的中间 4-7 位(共 4 位)替换为星号(****),仅保留前 3 位和后 4 位。
例如:13812345678 → 138****5678
2. 实现思路
- 使用正则分组:将 11 位手机号分为 3 个分组(前 3 位 + 中间 4 位 + 后 4 位),对应正则表达式
(\d{3})(\d{4})(\d{4}); - 调用
replaceAllIn方法:基于分组结果动态替换,保留分组 1(前 3 位)和分组 3(后 4 位),将分组 2(中间 4 位)替换为****。
3. 完整可运行代码
import scala.util.matching.Regex
object PhoneNumberMaskDemo {
def main(args: Array[String]): Unit = {
// 1. 定义包含多个手机号的目标文本
val originalText =
"""
|用户1:手机号13812345678
|用户2:手机号13987654321
|用户3:手机号18612345678
|用户4:手机号17798765432
|""".stripMargin
// 2. 定义手机号分组正则规则:(前3位)(中间4位)(后4位)
val phoneRegex: Regex = "(\d{3})(\d{4})(\d{4})".r
// 3. 调用replaceAllIn方法,基于分组动态打马赛克
val maskedText = phoneRegex.replaceAllIn(originalText, m => {
// m.group(1):获取第一个分组(前3位手机号)
// m.group(3):获取第三个分组(后4位手机号)
// 中间拼接****,实现脱敏
m.group(1) + "****" + m.group(3)
})
// 4. 输出结果对比
println("=== 手机号脱敏前后对比 ===")
println("【脱敏前】:")
println(originalText)
println("【脱敏后】:")
println(maskedText)
}
}
4. 关键说明
-
正则分组与
group方法:- 正则表达式中的
()对应分组索引,索引从 1 开始(group(0)表示整个匹配的手机号,如13812345678); m.group(1)对应第一个分组(\d{3}),即手机号前 3 位;m.group(2)对应第二个分组(\d{4}),即手机号中间 4 位(需要替换的部分);m.group(3)对应第三个分组(\d{4}),即手机号后 4 位。
- 正则表达式中的
-
运行结果:所有手机号均会实现脱敏,例如
13812345678变为138****5678,13987654321变为139****4321,有效保护用户隐私。 -
扩展性:若需调整脱敏位数(如中间 5 位打码),只需修改正则分组和替换逻辑即可,例如正则改为
(\d{3})(\d{5})(\d{3}),替换为m.group(1) + "*****" + m.group(3)。