一、Scala 中字符串的两种核心定义格式
Scala 支持不可变字符串(String) 和可变字符串(StringBuilder) 两类核心定义方式,同时字符串字面量有两种书写形式,具体如下:
1. 字面量定义(不可变,基于 Java String)
Scala 直接复用 Java 的 String 类型,不可变特性意味着字符串内容一旦创建无法修改,是最常用的方式。
- 双引号("") :标准格式,支持转义字符(
\n、\t、"等)。 - 三引号("""""") :原生字符串格式,无需转义,适合多行文本 / 含特殊字符的场景。
scala
// 1. 双引号定义(支持转义)
val str1: String = "Hello Scala!\n你好,Scala!"
println(str1)
// 输出:
// Hello Scala!
// 你好,Scala!
// 2. 三引号定义(原生字符串,无转义)
val str2: String = """Hello "Scala"!
路径:C:\scala\code"""
println(str2)
// 输出:
// Hello "Scala"!
// 路径:C:\scala\code
2. 可变字符串(StringBuilder)
用于频繁修改字符串的场景(如拼接、替换),避免不可变 String 频繁创建新对象的性能损耗:
scala
val sb = new StringBuilder("Hello")
sb.append(" Scala") // 追加
sb.insert(5, ",") // 插入
sb.update(0, 'h') // 修改字符
println(sb.toString) // 输出:hello, Scala
二、Scala 字符串常用方法
Scala 字符串(String 类型)兼容所有 Java String 方法,同时扩展了更简洁的 Scala 风格方法,核心常用方法如下:
| 方法 | 功能说明 | 示例 |
|---|---|---|
length | 获取字符串长度 | "abc".length → 3 |
charAt(index) | 获取指定索引的字符 | "abc".charAt(1) → 'b' |
substring(start[, end]) | 截取子串(end 可选,默认到末尾) | "abcde".substring(1,3) → "bc" |
split(regex) | 按正则分割字符串为数组 | "a,b,c".split(",") → Array("a","b","c") |
trim | 去除首尾空白字符 | " abc ".trim → "abc" |
stripPrefix/prefix | 去除前缀 / 判断前缀 | "scala.txt".stripPrefix("scala") → ".txt" |
stripSuffix/suffix | 去除后缀 / 判断后缀 | "scala.txt".endsWith("txt") → true |
replace(old, new) | 替换所有匹配的子串 | "abac".replace("a", "x") → "xbxc" |
replaceFirst/replaceAll | 正则替换(首次 / 全部) | "a1b2".replaceAll("\d", "") → "ab" |
toLowerCase/toUpperCase | 大小写转换 | "Scala".toUpperCase → "SCALA" |
contains(sub) | 判断是否包含子串 | "abc".contains("b") → true |
indexOf/substring | 查找子串索引(无则返回 -1) | "abc".indexOf("c") → 2 |
isEmpty/nonEmpty | 判断是否为空 / 非空 | "".isEmpty → true |
mkString | 集合转字符串(配合字符串拼接) | Array(1,2,3).mkString(",") → "1,2,3" |
interpolate | 字符串插值(s/f 插值器) | val name = "Scala"; s"Hello $name" → "Hello Scala" |
核心示例:
scala
// 1. 插值器(最常用)
val age = 20
val sStr = s"年龄:$age" // 普通插值 → "年龄:20"
val fStr = f"圆周率:${Math.PI}%.2f" // 格式化插值 → "圆周率:3.14"
val rawStr = raw"路径:C:\scala" // 原生插值(不转义)→ "路径:C:\scala"
// 2. 分割与拼接
val arr = "a,b,c".split(",") // Array("a","b","c")
val joinStr = arr.mkString("|") // "a|b|c"
// 3. 前缀/后缀判断
val fileName = "data.csv"
fileName.startsWith("data") // true
fileName.endsWith("csv") // true
// 4. 正则匹配
val regex = "^[0-9]{6}$".r // 6位数字正则
regex.matches("123456") // true
三、身份证号码的基本格式(中国大陆)
中国大陆居民身份证号分为 18 位(主流) 和 15 位(旧版,已逐步淘汰) ,核心规则如下:
1. 18 位身份证格式(GB11643-1999 标准)
结构:6位地址码 + 8位出生日期码 + 3位顺序码 + 1位校验码
| 部分 | 长度 | 说明 |
|---|---|---|
| 地址码 | 6 位 | 前 2 位:省级行政区代码(如 11 = 北京、31 = 上海);中间 2 位:市级;后 2 位:县级 |
| 出生日期码 | 8 位 | 格式为 YYYYMMDD(如 19900101=1990 年 1 月 1 日) |
| 顺序码 | 3 位 | 同一地区、同日出生人员的排序码;第 3 位奇数 = 男性,偶数 = 女性 |
| 校验码 | 1 位 | 0-9 或 X(大写),通过前 17 位计算得出(ISO 7064:1983.MOD 11-2 算法) |
2. 15 位身份证格式(旧版)
结构:6位地址码 + 6位出生日期码 + 3位顺序码
- 出生日期码:
YYMMDD(仅年份后两位,如 900101=1990 年 1 月 1 日); - 无校验码,顺序码规则同 18 位。
3. 关键校验规则(18 位)
校验码计算逻辑:
- 前 17 位每一位乘以加权因子(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2);
- 求和后对 11 取余,余数对应校验码:
0→1,1→0,2→X,3→9,4→8,5→7,6→6,7→5,8→4,9→3,10→2。
Scala 示例:身份证格式校验
scala
/**
* 校验18位身份证格式合法性
* @param idCard 18位身份证号
* @return 是否合法
*/
def isValidIdCard18(idCard: String): Boolean = {
// 1. 基础格式校验(18位,前17位数字,最后一位数字/X)
val idRegex = "^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))((0[1-9])|([12]\d)|(3[01]))\d{3}[0-9Xx]$".r
if (!idRegex.matches(idCard)) return false
// 2. 校验码验证
val weights = Array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2) // 前17位加权因子
val checkCodes = Array('1','0','X','9','8','7','6','5','4','3','2') // 余数对应校验码
val sum = idCard.take(17).zip(weights).map { case (c, w) => c.toString.toInt * w }.sum
val remainder = sum % 11
val actualCheckCode = idCard.last.toUpper // 统一转大写
actualCheckCode == checkCodes(remainder).toString
}
// 测试
println(isValidIdCard18("110101199001011234")) // 示例(需替换为真实合法号)
println(isValidIdCard18("11010119900101123X")) // 校验码为X的场景
总结
- 字符串定义:不可变(双引号 / 三引号)、可变(StringBuilder);
- 常用方法:插值、分割、拼接、正则、前缀 / 后缀判断等;
- 身份证格式:18 位(地址 + 生日 + 顺序 + 校验),15 位(无校验,生日 6 位),核心需校验格式和校验码。