Java开发笔记(三十八)利用正则表达式校验字符串

时间:2022-06-03 12:00:46

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

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

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

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

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

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

  5. Java学习笔记二十八&colon;Java中的接口

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

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

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

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

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

  8. Java开发笔记(十二)布尔变量论道与或非

    在编程语言的设计之初,它们除了可以进行数学计算,还常常用于逻辑推理和条件判断.为了实现逻辑判断的功能,Java引入了一种布尔类型boolean,用来表示“真”和“假”.该类型的变量只允许两个取值,即t ...

  9. Java开发笔记(十六)非此即彼的条件分支

    前面花了大量篇幅介绍布尔类型及相应的关系运算和逻辑运算,那可不仅仅是为了求真值或假值,更是为了通过布尔值控制流程的走向.在现实生活中,常常需要在岔路口抉择走去何方,往南还是往北,向东还是向西?在Jav ...

随机推荐

  1. &lbrack;LeetCode&rsqb; 8&period; String to Integer &lpar;atoi&rpar;

    Implement atoi to convert a string to an integer. public class Solution { public int myAtoi(String s ...

  2. Android Viewpager PagerAdapter update data 刷新界面数据

    最近做的项目涉及到ViewPager数据刷新,网上的资料挺多,但是和现在做的这个不太相同,所以并没有找到有效的. 折腾了大半天,整理一下思路: 问题1: 后台刷新数据次数过多后,界面出现卡顿现象,判断 ...

  3. WordPress D8 主题当中截取文章首图并显示的函数

    取自 WordPress D8 主题; 路径 theme\d8\modules ; if ( ! function_exists( 'deel_thumbnail' ) ) : function de ...

  4. 好用的QT连接

    QT属性控件项目https://github.com/lexxmark/QtnProperty比特币交易软件https://github.com/JulyIGHOR/QtBitcoinTrader导航 ...

  5. UnixShell编程&lpar;第三版&rpar; 二章

    这本书写的真的很好,让人欲罢不能的读下去. 1,可以简单的将命令看做类似函数的东西,而后面跟的是所传的参数. echo Hello Word > Hi   将字符串hello Wrod 写入文件 ...

  6. operation is executing and cannot be enqueued

    http://d2100.com/questions/29022 作为依赖关系的另一个 NSOperation 添加时不调用 NSOperation dealloc 使用文书我看到很多我自定义的 NS ...

  7. 欧几里德欧几里德原理和扩展的原则,&lpar;Euclidean Theory and Extended Euclidean Theory&rpar;学习笔记

    题记:这是我第四次审查扩展欧几里德原理,由于不经常使用.当你想使用,可以不记得细节,经常检查信息,所以,简单地梳理这一原则和扩展欧几里德的原则,以博客存档以备查用. 一个.欧几里德原理 欧几里德原理( ...

  8. Socket网络编程基本介绍

    一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...

  9. 连接mysql 数据库时出现2003 -can&&num;39&semi;t connect to mysql server on &&num;39&semi;localhost&&num;39&semi;&lpar;100038&rpar;的问题

    通过eclipse连接数据库是出现了以下问题 可能是由于数据库未开启造成的,你需要手动开启数据库. 手动开启数据库的方法: 1 win+r键后,在cmd中输入services.msc,点击确定 点击左 ...

  10. vdscode连接git服务器&lpar;以码云为例&rpar;

    准备工作:先下载并安装git客户端 1.在码云或者github上新建项目,获得新建项目的地址,得到一个类似:https://gitee.com/zhangshitongsky/vueTest.git ...