实名认证时,常会用到身份证号码和车牌号码的正则表达式匹配验证。简单高效。
经过一次一次的测试,去除多种匹配的表达式,得出相对正确的正则表达式。
1.车牌号正则匹配
车牌号组成规则
1.民用常规车牌号
常规车牌号由三部分组成,仅允许以汉字开头,后面可录入六个字符,由大写英文字母和阿拉伯数字组成。如:浙A 12345
如下图:
随着车辆的增多,五位序号码已经排满,英文字母都分配或者预留给下辖县市了,市区只好再继续数字字头,不过第二位是英文字母,就是浙A-0A001排列到浙A-0Z999。
2.新军车牌
以两位为大写英文字母开头,后面以5位阿拉伯数字组成。如:BA12345。
3.最后一位为汉字的车牌
有最后一位为汉字的车牌,比如外国大使馆的车牌后面的汉字是个领字,咱们中国警察后面是个警字,挂车后面有个挂字
允许以汉字开头,后面可录入六个字符,前五位字符,由大写英文字母和阿拉伯数字组成,而最后一个字符为汉字。
汉字包括“挂”、“学”、“警”、“港”、“澳”,“领”。如:浙A1234警
4.新能源汽车车牌
新能源汽车车牌新增加两个字段D(表示纯电动)和F(表示非纯电动),小型轿车字段在前面,如:浙AD12345,浙AF12345,大型车字段在后面,如浙A12345D,浙A12345F。
新能源车牌比普通车牌号多一位。
综上:常用车牌号的正则表达式为:
regex=([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][DF]?[A-Z0-9]{4}[A-Z0-9挂学警港澳领][DF]?)
由于开头两位英文字母后面四位字符的这种情况匹配错误率较高,所以舍弃了这种车牌的匹配,正则表达式为:
regex=([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][DF]?[A-Z0-9]{4}[A-Z0-9挂学警港澳领][DF]?)
问题:
写在XML文件中的正则,C++程序读取表达式集合[]中的汉字匹配出现问题,不能准确的匹配汉字。
解决:
将集合[]改为捕获型或者非捕获型括号后,汉字使用或(|)隔离,可以正确匹配汉字。
如下:
regex=((京|津|沪|渝|冀|豫|云|辽|黑|湘|皖|鲁|新|苏|浙|赣|鄂|桂|甘|晋|蒙|陕|吉|闽|贵|粤|青|藏|川|宁|琼|使|领)[A-Z][DF]?[A-Z0-9]{4}[A-Z0-9挂学警港澳领][DF]?)
2.身份证号码分步验证
身份证号码说明
公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
-
1.1.地址码规则:
地址码长6位
以数字1-9开头
后5位为0-9的数字所以,地址码的正则表达式为:
[1-9]\d{5}
-
1.2 年份码规则:
年份码长4位
以数字18,19或20开头
剩余两位为0-9的数字所以,年份码的正则表达式:
(18|19|20)\d{2}
。如果不需要18开头的年份,可以去掉18。 -
1.3 月份码规则:
月份码长2位
第一位数字为0,第二位数字为1-9
或者第一位数字为1,第二位数字为0-2所以,月份码的正则表达式:
((0[1-9])|(1[0-2]))
。 -
1.4 日期码规则:
日期码长2位
第一位数字为0-2,第二位数字为1-9
或者是10,20,30,31所以,日期码的正则表达式 :
(([0-2][1-9])|10|20|30|31)
。 -
1.5 顺序码规则:
顺序码长3位
顺序码是数字所以,顺序码的正则表达式 :
\d{3}
。 -
1.6 校验码规则:
校验码长1位
可以是数字,字母x或字母X所以,校验码的正则表达式 :
[0-9Xx]
。
综上,身份证号码完整的正则表达式为:
regex=([1-9]\d{5}(?:18|19|20)\d{2}(?:(?:0[1-9])|(?:1[0-2]))(?:(?:[0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])
我们实际项目XML文档中正则默认全匹配,所以不需要非捕获括号。19世纪的人群身份证号码也舍弃。
因此身份证号码的完成正则表达式为:
regex=([1-9]\d{5}(19|20)\d{2}((?:0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])
前面六位地址为还可以再一步精确。
地址前两位分别为:
province={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:"新疆",71:"台湾",81:"香港",82:"澳门"};
根据各个省份前两位地址码可以判定第一位范围1-8,第二位只有重庆是0,其余范围是1-7。因此表达式为:
regex=(([1-8][1-7]|50)\d{4}(19|20)\d{2}((?:0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])
想要再一步精确,可以在首尾加上限定,首尾都是非数字非字母。正则表达式如下:
regex=[^\w](([1-8][1-7]|50)\d{4}(19|20)\d{2}((?:0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])[^\w]
上面正则存在两点不足:
1.地址码不够准确
我国不存在16,26开头的地区,但是仍然可以通过上面验证。
2.月份日期判断不够精确
2月份不存在31日,上面表达式仍然可以通过。
解决:
特殊情况不多的情况下,写程序时可以if判断语句排除这几种情况。
哈哈:每天进步一点点、开心一点点、快乐一点点、good come on!