业务过程中,遇到了身份证判断是否有效的问题。如能连接公安系统进行身份证判断,自然是最准确的,但是这对普通码农来讲是不现实的。
现根据大陆身份证号码规律,自己写判断规则,利用正则表达式来判断给定的字符串是否是近似一个有效的身份证号码。并将代码封装为一个mysql函数,方便代码复用。
注意:本代码所用规则根据一代、二代身份证的数字规律进行建立,只能近似保证号码判断的准确性、排除大多数录入数据不规则的的情况,但针对少数符合规则但属于无效的情况,这里无法判断。
废话少说,直接上码:
delimiter $$
use `analysis`$$
drop function if exists `is_id_card`$$
create definer=`lws`@`%` function `is_id_card`(number varchar(20)charset utf8) returns tinyint(1)
begin
declare flag bool default false;
if (length(number)=18
and number regexp concat('^(([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([1][0-4])|([6][1-6])|([7][1])|([8][1-2]))', -- 1、2位
'(([0][0-9])|([1][0-9])|([2][0-9])|([3][0-9])|([4][0-3])|([5][1-3])|([8][2])|([9][0]|[1]|[9]))', -- 3、4位
'(([0-3][0-9])|([4][0-4])|([5][1])|([8][1-9])|([9][0-9]))', -- 5、6位
'(([1]([8]|[9])[0-9])|([2]([0]|[0-1])[0-9]))[0-9](0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[0-9]{3}([0-9]|x)') -- 后12位
or (length(number)=15
and number regexp concat('^(([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([1][0-4])|([6][1-6])|([7][1])|([8][1-2]))',
'(([0][0-9])|([1][0-9])|([2][0-9])|([3][0-9])|([4][0-3])|([5][1-3])|([8][2])|([9][0]|[1]|[9]))',
'(([0-3][0-9])|([4][0-4])|([5][1])|([8][1-9])|([9][0-9]))',
'(0[1-9]|[1-9][0-9])(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[0-9]{3}')))
then set flag = true;
end if;
return flag;
end$$
delimiter ;
大家把上述代码保存为一个mysql函数,然后调用该函数即可。
使用方法:
select is_id_card('这里输入需要验证的身份证号码')
这里分18位身份证号码、15位身份证号码两种情况:
- 它们前六位一致,都是省级代码(前两位)、地市级代码(前4位)、县区级代码(前6位);
- 出生年月日方面,18位身份证是形如1990xxxx的格式,而15位身份证是形如79xxxx的格式,也即后者省去了年份的前两位;
- 18位身份证最后一位是校验码,可为数字或者x,而15位身份证没有最后一位校验码。
值的注意的是,代码中的正则表达式字符串由于过长,这里使用了一个小窍门来进行换行显示,以提高代码可读性:
先把原来的一个长正则表达式拆分为几个,再使用concat()函数连接起来,因为concat()函数内部参数之间是可以任意换行的,所以就变相实现了原字符串的换行。这一点,在以后遇到字符串需要换行的时候可以使用。
========================= 2019-06-26更新分割线==============================
鉴于上述函数不能覆盖全部情况,导致部分身份证判别错误,现在重新编写了一个进阶版,此版本需要额外的新政划分表,可点此下载:
(链接: https://pan.baidu.com/s/1irx3jzulejkbd6qx2tnl5w 提取码: 6ynv 复制这段内容后打开百度网盘手机app,操作更方便哦)。
先上函数代码:
delimiter $$
use `analysis`$$
drop function if exists `is_id_card`$$
create function `is_id_card`(number varchar(20)charset utf8) returns tinyint(1)
begin
declare flag bool default false;
if (length(number)=18
and substr(number,1,6) in (select b.district_id from administrative_division_code b where b.flag=1)
and number regexp concat('^[1-9][0-9]{5}',
'(([1]([8]|[9])[0-9])|([2]([0]|[0-1])[0-9]))[0-9](0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[0-9]{3}([0-9]|x)') -- 后12位
or (length(number)=15
and substr(number,1,6) in (select b.district_id from administrative_division_code b where b.flag=1)
and number regexp concat('^[1-9][0-9]{5}',
'(0[1-9]|[1-9][0-9])(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[0-9]{3}')))
then set flag = true;
end if;
return flag;
end$$
delimiter ;
注意:上述函数需要使用表—— administrative_division_code ,下载后,放在你自己的数据库中即可。