在日常开发和数据处理场景中,身份证号是蕴含丰富个人信息的 “数据载体”。基于 18 位身份证号的编码规则,我们可以解析出性别、年龄、籍贯甚至星座等信息。本文将基于Scala 语言,从零搭建一个身份证号信息解析工具,带你吃透字符串截取、模式匹配等核心语法,同时实现实用的多维度信息提取功能。
一、身份证号编码规则与解析思路
要实现解析功能,首先得搞懂身份证号的编码逻辑,这是开发的核心依据:
- 长度规则:中国大陆标准身份证号为18 位,前 17 位为数字,最后一位可为数字或
X/x - 地域编码:前 2 位代表省级行政区
- 出生日期:第 7-14 位为出生年月日
- 性别标识:第 17 位为性别位,奇数为男性,偶数为女性
- 校验码:第 18 位为校验位,用于验证身份证号合法性
基于以上规则,我们的工具将实现5 大核心功能:合法性校验、性别判断、年龄计算、省份匹配、星座判断
二、技术选型与语法
本次会用到 Scala 的几个核心特性,也是函数式编程的典型体现:
substring方法:精准截取身份证号不同位置的字符段,实现信息提取;- 不可变 Map:存储省级行政区编码与名称的映射关系,保证数据安全;
- 模式匹配 :优雅实现星座的日期区间判断,替代繁琐的
if-else; LocalDate类:获取当前年份,完成年龄的动态计算;try-catch异常处理:捕获数字转换异常,提升程序健壮性。
三、完整代码
下面是可直接运行的完整代码,已添加注释和用户友好的交互逻辑:
// 导入日期工具类,用于获取当前年份
import java.time.LocalDate
/**
* 身份证号信息解析工具
* 支持性别、年龄、省份、星座多维度解析,含异常处理和退出机制
*/
object IDCardAnalyzer {
def main(args: Array[String]): Unit = {
println("=== 身份证号信息解析工具 ===")
println("提示:输入18位身份证号解析信息,输入exit可退出程序\n")
// 循环接收用户输入,实现持续解析
while (true) {
val inputId = scala.io.StdIn.readLine("请输入身份证号:").trim
// 退出逻辑:不区分大小写匹配exit
if (inputId.equalsIgnoreCase("exit")) {
println("\n程序已退出,感谢使用!")
return
}
// 第一步:校验身份证号长度合法性
if (inputId.length != 18) {
println(s"错误:${inputId}长度非18位,不是合法身份证号!\n")
continue
}
try {
// 1. 性别解析:截取第17位(下标16),奇数为男,偶数为女
val genderCode = inputId.substring(16, 17).toInt
val gender = if (genderCode % 2 == 1) "男性(小哥)" else "女性(姑娘)"
// 2. 年龄解析:截取第7-10位出生年份,计算与当前年份差值
val birthYear = inputId.substring(6, 10).toInt
val currentYear = LocalDate.now().getYear
val age = currentYear - birthYear
// 3. 省份解析:通过前2位编码匹配省级行政区
val provinceCode = inputId.substring(0, 2)
val regionMap: Map[String, String] = Map(
"11" -> "北京市", "12" -> "天津市", "13" -> "河北省",
"14" -> "山西省", "15" -> "内蒙古自治区", "21" -> "辽宁省",
"22" -> "吉林省", "23" -> "黑龙江省", "31" -> "上海市",
"32" -> "江苏省", "33" -> "浙江省", "34" -> "安徽省",
"35" -> "福建省", "36" -> "江西省", "37" -> "山东省",
"41" -> "河南省", "42" -> "湖北省", "43" -> "湖南省",
"44" -> "广东省", "45" -> "广西壮族自治区", "46" -> "海南省",
"50" -> "重庆市", "51" -> "四川省", "52" -> "贵州省",
"53" -> "云南省", "54" -> "西藏自治区", "61" -> "陕西省",
"62" -> "甘肃省", "63" -> "青海省", "64" -> "宁夏回族自治区",
"65" -> "新疆维吾尔自治区"
)
val province = regionMap.getOrElse(provinceCode, s"未知地区(编码${provinceCode})")
// 4. 星座解析:截取出生月日,调用工具方法匹配星座
val birthMonth = inputId.substring(10, 12).toInt
val birthDay = inputId.substring(12, 14).toInt
val constellation = getConstellation(birthMonth, birthDay)
// 输出解析结果,格式化提升可读性
println("\n解析成功!")
println(s"身份证号:${inputId}")
println(s"性别:${gender}")
println(s"年龄:${age}岁(出生于${birthYear}年)")
println(s"籍贯:${province}")
println(s"星座:${constellation}\n")
} catch {
// 捕获非数字转换异常(兼容最后一位X/x)
case e: NumberFormatException =>
val lastChar = inputId.charAt(17)
if (lastChar == 'X' || lastChar == 'x') {
println("提示:身份证号最后一位为X/x,已忽略该位校验,请重新输入完整信息!\n")
} else {
println("错误:身份证号含非数字字符!\n")
}
}
}
}
/**
* 星座匹配工具方法
* @param month 出生月
* @param day 出生日期
* @return 对应星座名称
*/
private def getConstellation(month: Int, day: Int): String = {
(month, day) match {
case (1, d) if d >= 20 => "水瓶座"
case (2, d) if d <= 18 => "水瓶座"
case (2, d) if d >= 19 => "双鱼座"
case (3, d) if d <= 20 => "双鱼座"
case (3, d) if d >= 21 => "白羊座"
case (4, d) if d <= 19 => "白羊座"
case (4, d) if d >= 20 => "金牛座"
case (5, d) if d <= 20 => "金牛座"
case (5, d) if d >= 21 => "双子座"
case (6, d) if d <= 21 => "双子座"
case (6, d) if d >= 22 => "巨蟹座"
case (7, d) if d <= 22 => "巨蟹座"
case (7, d) if d >= 23 => "狮子座"
case (8, d) if d <= 22 => "狮子座"
case (8, d) if d >= 23 => "处女座"
case (9, d) if d <= 22 => "处女座"
case (9, d) if d >= 23 => "天秤座"
case (10, d) if d <= 23 => "天秤座"
case (10, d) if d >= 24 => "天蝎座"
case (11, d) if d <= 22 => "天蝎座"
case (11, d) if d >= 23 => "射手座"
case (12, d) if d <= 21 => "射手座"
case _ => "摩羯座"
}
}
}
四、功能拆解
1. 合法性校验
程序首先校验输入长度是否为 18 位,非 18 位直接返回错误提示,这是最基础的合法性判断。同时通过try-catch捕获NumberFormatException,兼容最后一位的X/x校验码
2. 性别解析
身份证第 17 位为性别位,通过substring(16,17)截取该字符并转为数字,再通过取模运算%2判断奇偶,实现性别区分
3. 年龄解析
截取第 7-10 位的出生年份,结合LocalDate.now().getYear()获取的当前年份,通过差值计算年龄
4. 省份解析
通过不可变 Map 存储全国 34 个省级行政区的编码映射,使用getOrElse方法实现 “匹配到返回名称,匹配不到返回未知” 的兜底逻辑,避免空指针异常
5. 星座解析
自定义getConstellation方法,利用 Scala 的模式匹配特性,按星座的日期区间逐一匹配,相比多层if-else更简洁易维护
五、运行测试
1. 合法输入测试
输入示例:11010119990520701X输出结果:
解析成功!
身份证号:11010119990520701X
性别:男性(小哥)
年龄:26岁(出生于1999年)
籍贯:北京市
星座:金牛座
2. 非法输入测试
输入示例:12345输出结果:
错误:12345长度非18位,不是合法身份证号!
六、功能扩展
- 精准年龄计算:解析完整生日,对比当前日期判断生日是否已过,实现精确到天的年龄计算
- 完整合法性校验:引入身份证号校验算法,验证第 18 位校验码的合法性
- 地区多级解析:补充前 6 位行政区划编码,实现省、市、区三级地域解析
- GUI 界面封装:结合 ScalaFX 等框架,开发可视化操作界面,提升用户体验
总结
本文通过一个实用的身份证号解析工具,实现了多维度信息提取,深度实践了 Scala 的字符串操作、模式匹配、异常处理等核心语法。该代码可直接用于数据清洗、用户信息预处理等场景,也可根据实际需求进一步扩展功能。希望这篇文章能帮你夯实 Scala 基础,同时掌握实用的业务开发技巧