Java开发笔记(三十八)利用正则表达式校验字符串
前面多次提到了正则串、正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了上述规则的所有字符串。正则表达式的保留字符主要有:圆括号、方括号、花括号、竖线、横线、点号、加号、星号、反斜杆等等,这些保留字符的作用详见前一篇博文,下面再简单总结一下它们的用途:
圆括号“()”:把圆括号内外的表达式区别开来。
方括号“[]”:表示方括号内部的字符互相之间是或的关系。
花括号“{}”:花括号中间填写数字,表示花括号前面的字符有多少位。
竖线“|”:对前面和后面的字符进行或运算,表示既可以是前面的字符,也可以是后面的字符。
横线“-”:与前面和后面的字符组合起来,代表两个字符之间的所有连续字符。
点号“.”:代表除了回车符和换行符以外的其它字符。
加号“+”:表示加号前面的字符可以有一位,也可以有多位。
星号“*”:表示星号前面的字符可以有一位,也可以有多位,还可以没有(0位)。
反斜杆“\”:两个反斜杆可对保留字符进行转义,表示保留字符的自身符号。
正则表达式除了用在split方法中切割字符串,还可以用在matches方法中判断字符串是否符合正则条件。以手机号码为例,不管是移动还是联通还是电信的手机号,统统都是11位数字,并且第一位数字固定为1,第二位数字可能是3、4、5、7、8,再加上9位数字凑成11位手机号。那么通过正则表达式书写11位手机号码的规则,第一位就用“1”表示,第二位可用“[34578]”表示,后面的9位数字使用“\\d{9}”表达,整合起来便形成了最终的手机号码正则串“1[34578]\\d{9}”。下面的isPhone方法,就是根据这个正则表达式校验手机号码的代码例子:
// 利用正则表达式检查字符串是否为合法的手机号码
public static boolean isPhone(String phone) {
// 开头的"1"代表第一位为数字1,"[34578]"代表第二位可以为3、4、5、7、8其中之一,"\\d{9}"代表后面是9位数字
String regex = "1[34578]\\d{9}";
// 字符串变量的matches方法返回正则表达式对该串的检验结果,true表示符合字符串规则,false表示不符合规则
return phone.matches(regex);
}
再来一个更复杂的字符串校验——身份证号码的格式校验,中国的二代身份证号码共有18位,其中前六位是地区编码,中间八位是公民的出生年月日,后面三位是该地区当日的出生序号,最后一位是校验码。国家把各省区划分为七大块,地区编码的首位为1代表华北地区,为2代表东北地区,为3代表华东地区,为4代表中南地区,为5代表西南地区,为6代表西北地区,为8代表港澳台特别行政区。地区编码的第二位代表大区域下面的具体省区,再后面的位数表示下面的地市乃至县区,通常只要校验地区编码的前两位就行了,于是得到如下的地区校验的正则方法代码例子:
// 校验身份证号码开头的六位地区编码
public static void checkArea() {
String regex = "(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|8[1-3])\\d{4}";
for (int i=0; i<=90; i++) {
String area = String.format("%06d", i*10000);
boolean check = area.matches(regex);
System.out.println("area = "+area+", check = "+check);
}
}
身份证号码中间的八位出生年月日,可再拆分为四位的年份、两位的月份和两位的日期。一个健在公民的出生年份,只可能是二十世纪和二十一世纪的某一年,也就是说,四位年份必定以19或者20开头,因此正则串“(19|20)\\d{2}”即可覆盖这两个世纪的两百个年份。此时校验年份的正则方法代码如下所示:
// 校验四位的年份字符串
public static void checkYear() {
String regex = "(19|20)\\d{2}";
for (int i=1899; i<=2100; i++) {
if (i>1910 && i<2090) {
continue;
}
String year = i+"";
boolean check = year.matches(regex);
System.out.println("year = "+year+", check = "+check);
}
}
年份校验完毕,后面的月份更简单,因为两位月份就是“01”到“12”中间的十二个数字。如果月份首位是0,那么第二位可以是1到9;如果月份首位是1,那么第二位可以是0到2。据此可把月份的正则表达式分解成两个关系为“或”的子表达式,其中第一个表达式可使用“0[1-9]”,第二个表达式可使用“1[0-2]”,两个表达式通过竖线连接起来便形成了完整的月份表达式“0[1-9]|1[0-2]”。此时校验月份的正则方法代码如下所示:
// 校验两位的月份字符串
public static void checkMonth() {
String regex = "0[1-9]|1[0-2]";
for (int i=0; i<=13; i++) {
String month = String.format("%02d", i);
boolean check = month.matches(regex);
System.out.println("month = "+month+", check = "+check);
}
}
月份后面的日期,校验起来稍微有些复杂。合法的两位日期可以是“01”到“31”中间的三十一个数字,故而日期的正则校验需要分解成以下的三种情况:
1、日期首位是0,那么第二位可以是1到9,该情况的正则表达式应为“0[1-9]”。
2、日期首位是1或者2,那么第二位可以是0到9,该情况的正则表达式应为“[12]\\d”。
3、日期首位是3,那么第二位可以是0和1,该情况的正则表达式应为“3[01]”。
综合以上的三种情况,得到完整的日期校验正则串为“0[1-9]|[12]\\d|3[01]”。此时校验日期的正则方法代码如下所示:
// 校验两位的日期字符串
public static void checkDay() {
String regex = "0[1-9]|[12]\\d|3[01]";
for (int i=0; i<=32; i++) {
String day = String.format("%02d", i);
boolean check = day.matches(regex);
System.out.println("day = "+day+", check = "+check);
}
}
然后还要校验身份证号码的末尾四位,包括三位的出生编码和一位的校验码。其中出生编码为三位数字,而校验码除了数字以外还可能是小写的x或者大写的X,因此出生编码和校验码也得分别加以判断。三位的出生编码,对应的正则表达式为“\\d{3}”;一位的校验码,对应的正则表达式为“[0-9xX]”;二者的式子合起来,就变成了“\\d{3}([0-9xX])”。下面的方法代码可生成四位的字符串,并进行身份证末四位的正则校验:
// 校验身份证号码末尾的四位编号串
public static void checkLastFour() {
String regex = "\\d{3}([0-9xX])";
for (int i=0; i<36; i++) {
char last;
if (i < 10) {
// 转换成数字字符
last = (char) ('0'+i);
} else {
// 转换成字母字符
last = (char) ('A' + i-10);
}
String lastFour = String.format("%03d%c", i*13, last);
boolean check = lastFour.matches(regex);
System.out.println("lastFour = "+lastFour+", check = "+check);
}
}
以上把18位身份证号码的各个区间分别做了正则校验,最后还要组装各区间的正则表达式。这时为了避免各区间的表达式互相干扰,可以利用圆括号将各区间的作用范围先行界定,就像下面这样“(六位地区编码)(四位年份)(两位月份)(两位日期)(末尾四位编号)”,接着再把各区间的正则表达式分别填入该区间的圆括号之中,便形成了最终的身份证号码正则串。包含正则串在内的身份证校验的完整方法如下所示:
// 利用正则表达式检查字符串是否为合法的身份证号码
public static boolean isICNO(String icno) {
//String regex = "(六位地区编码)(四位年份)(两位月份)(两位日期)(末尾四位编号)";
String regex = "((1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|8[1-3])\\d{4})((19|20)\\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])(\\d{3}([0-9xX]))";
return icno.matches(regex);
}
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(三十八)利用正则表达式校验字符串的更多相关文章
- Java开发笔记(十八)上下求索的while循环
循环是流程控制的又一重要结构,“白天-黑夜-白天-黑夜”属于时间上的循环,古人“年复一年.日复一日”的“日出而作.日落而息”便是每天周而复始的生活.计算机程序处理循环结构时,给定一段每次都要执行的代码 ...
- Java开发学习(三十六)----SpringBoot三种配置文件解析
一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...
- Java开发笔记(九十八)利用Callable启动线程
前面介绍了如何利用Runnable接口构建线程任务,该方式确实方便了线程代码的复用与共享,然而Runnable不像公共方法那样有返回值,也就无法将线程代码的处理结果传给外部,造成外部既不知晓该线程是否 ...
- Java开发笔记(十三)利用关系运算符比较大小
前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...
- Java开发学习(二十八)----拦截器(Interceptor)详细解析
一.拦截器概念 讲解拦截器的概念之前,我们先看一张图: (1)浏览器发送一个请求会先到Tomcat的web服务器 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源 (3)如 ...
- 安卓开发笔记(十八):实现button按钮事件的三种方法
Android开发中有三种主要的方式用于设置View的点击事件,1.创建内部类:2.主类中实现OnClickListener接口:3.使用匿名内部类.这三种方式都用到了OnClickListener接 ...
- Java学习笔记二十八:Java中的接口
Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...
- Java学习笔记(十八)——Java DTO
[前面的话] 在和技术人员的交流中,各种专业术语会出现,每次都是默默的记录下出现的术语,然后再去网上查看是什么意思.最近做项目,需要使用到DTO,然后学习一下吧. 这篇文章是关于Java DTO的,选 ...
- 【Java学习笔记之十八】Javadoc注释的用法
Javadoc注释的用法 Java 文档 // 注释一行/* ...... */ 注释若干行/** ...... */ 注释若干行,并写入 javadoc 文档 通常这种注释的多行写法如下: /*** ...
随机推荐
- Django+wechatpy接入微信公众平台以及授权登录
确定Django环境可以正常运行,环境搭建见:Linux 搭建Nginx+uwsgi+Django环境 安装 wechatpy[cryptography] sudo pip3 install wech ...
- 怎么用JQUERY设置div背景图片?
平常,在css里,我们写成 { background:url(....) ; } 如果需要写脚本, 则 function(){ .....; $(....).css("background- ...
- JavaScript递归函数解“汉诺塔”
“汉诺塔”是一个著名的益智游戏.塔上有3根柱子和一套直径各不相同的空心圆盘.开始时柱子上的所有圆盘都按照从小到大的顺序堆叠.目标是通过每次移动一个圆盘到另一根柱子,最终把一堆圆盘移动到目标柱子上,过程 ...
- Oracle expdp数据泵导出,并在文件上附加上日期格式
一.导出操作的计算机要安装Oracle Client(建议管理员版本) 二.在服务端创建目录 create directory dpdir as '目录'; 三.给目录赋权限 grant read,w ...
- Mesos源码分析(15): Test Executor的运行
Test Executor的代码在src/examples/test_executor.cpp中 int main(int argc, char** argv) { TestExecutor ...
- 在ASP.NET Core中使用brotli压缩
Brotli是一种全新的数据格式,可以提供比Zopfli高20-26%的压缩比.据谷歌研究,Brotli压缩速度同zlib的Deflate实现大致相同,而在Canterbury语料库上的压缩密度比LZ ...
- Android单元测试之三:使用模拟框架模拟依赖
Android单元测试之三:使用模拟框架模拟依赖 基本描述 如果是一些工具类方法的测试,如计算两数之和的方法,本地 JVM 虚拟机就能提供足够的运行环境,但如果要测试的单元依赖了 Android 框架 ...
- Web前端-JavaScript基础教程上
Web前端-JavaScript基础教程 将放入菜单栏中,便于阅读! JavaScript是web前端开发的编程语言,大多数网站都使用到了JavaScript,所以我们要进行学习,JavaScript ...
- CSS3禁止用户选中文字——user-select: none;
需求:现在有一个需求是在移动端让你禁止用户选中文字,你会怎么做呢?如下图 解决方法:使用CSS3新增属性 user-select: none; -webkit-user-select:non ...
- [Swift]LeetCode152. 乘积最大子序列 | Maximum Product Subarray
Given an integer array nums, find the contiguous subarray within an array (containing at least one n ...