前面多次提到了正则串、正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了上述规则的所有字符串。正则表达式的保留字符主要有:圆括号、方括号、花括号、竖线、横线、点号、加号、星号、反斜杆等等,这些保留字符的作用详见前一篇博文,下面再简单总结一下它们的用途:
圆括号“()”:把圆括号内外的表达式区别开来。
方括号“[]”:表示方括号内部的字符互相之间是或的关系。
花括号“{}”:花括号中间填写数字,表示花括号前面的字符有多少位。
竖线“|”:对前面和后面的字符进行或运算,表示既可以是前面的字符,也可以是后面的字符。
横线“-”:与前面和后面的字符组合起来,代表两个字符之间的所有连续字符。
点号“.”:代表除了回车符和换行符以外的其它字符。
加号“+”:表示加号前面的字符可以有一位,也可以有多位。
星号“*”:表示星号前面的字符可以有一位,也可以有多位,还可以没有(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开发笔记(三十八)利用正则表达式校验字符串的更多相关文章

  1. Java开发笔记(十八)上下求索的while循环

    循环是流程控制的又一重要结构,“白天-黑夜-白天-黑夜”属于时间上的循环,古人“年复一年.日复一日”的“日出而作.日落而息”便是每天周而复始的生活.计算机程序处理循环结构时,给定一段每次都要执行的代码 ...

  2. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  3. Java开发笔记(九十八)利用Callable启动线程

    前面介绍了如何利用Runnable接口构建线程任务,该方式确实方便了线程代码的复用与共享,然而Runnable不像公共方法那样有返回值,也就无法将线程代码的处理结果传给外部,造成外部既不知晓该线程是否 ...

  4. Java开发笔记(十三)利用关系运算符比较大小

    前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...

  5. Java开发学习(二十八)----拦截器(Interceptor)详细解析

    一.拦截器概念 讲解拦截器的概念之前,我们先看一张图: (1)浏览器发送一个请求会先到Tomcat的web服务器 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源 (3)如 ...

  6. 安卓开发笔记(十八):实现button按钮事件的三种方法

    Android开发中有三种主要的方式用于设置View的点击事件,1.创建内部类:2.主类中实现OnClickListener接口:3.使用匿名内部类.这三种方式都用到了OnClickListener接 ...

  7. Java学习笔记二十八:Java中的接口

    Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...

  8. Java学习笔记(十八)——Java DTO

    [前面的话] 在和技术人员的交流中,各种专业术语会出现,每次都是默默的记录下出现的术语,然后再去网上查看是什么意思.最近做项目,需要使用到DTO,然后学习一下吧. 这篇文章是关于Java DTO的,选 ...

  9. 【Java学习笔记之十八】Javadoc注释的用法

    Javadoc注释的用法 Java 文档 // 注释一行/* ...... */ 注释若干行/** ...... */ 注释若干行,并写入 javadoc 文档 通常这种注释的多行写法如下: /*** ...

随机推荐

  1. python爬虫第五天

            cookie           我们访问网页是通过http协议进行的,而http协议是一个无状态协议(无法维持会话之间的状态),比如我们登录一个网站成功后访问另一个网页,那么登录状态 ...

  2. HelloPython

    HELLOWORD!你好!Python! 学习Python已有一段时间,一个人自学颇不容易,在此分享一些自己学习经验和感受,温故而知新,也希望自己能有些新收获. 学习Python,大多数人创建的第一个 ...

  3. Golang Go Go Go part3:数据类型及操作

    五.Go 基本类型 1.基本类型种类 布尔值: bool 长度 1字节 取值范围 true, false注意事项:不可用数字代表 true 或 false 整型: int/uint 根据运行平台可能为 ...

  4. [lua][openresty]代码覆盖率检测的解决方式

    废话在前 什么是代码覆盖率 来自百度百科 代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率. 开发人员为何关注? 在我们的开发过 ...

  5. [Swift]LeetCode115. 不同的子序列 | Distinct Subsequences

    Given a string S and a string T, count the number of distinct subsequences of S which equals T. A su ...

  6. [Swift]LeetCode227. 基本计算器 II | Basic Calculator II

    Implement a basic calculator to evaluate a simple expression string. The expression string contains ...

  7. [Swift]LeetCode889. 根据前序和后序遍历构造二叉树 | Construct Binary Tree from Preorder and Postorder Traversal

    Return any binary tree that matches the given preorder and postorder traversals. Values in the trave ...

  8. dedecms搜索模板,使用{dede:list}标签调用自定义字段不显示(空白)

    前几天使用织梦做一个搜索功能,正常使用{dede:list}调用自定义内容模型中的自定义字段,代码如下:(自定义字段的调用可以参考:http://www.dede58.com/a/dedejq/523 ...

  9. ASP.NET Core 系列目录

    目录: ASP.NET Core 2.0 : 一. 概述 ASP.NET Core 2.0:二. 开发环境 ASP.NET Core 2.0 : 三. 项目结构 ASP.NET Core 2.0 : ...

  10. 高可用Eureka注册中心配置说明(双机部署)

    目  录 1. 高可用EureKa注册中心示意图 2. Eureka实例相互注册配置 3. 微服务注册到Eureka配置 4. 启动步骤及配置成功检查 5. 说明事项 1. 高可用EureKa注册中心 ...