1、SFZ验证规则
18位SFZ号码由十七位数字本体码和一位数字校验码组成。
排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
其校验码(最后一位)计算方法和步骤为:
(1)十七位数字本体码加权求和公式
S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
其中Ai:表示第i位置上的SFZ号码数字值
Wi:表示第i位置上的加权因子,前17位加权因子从左到右分别为 :7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(2)计算模 Y = mod(S, 11)
(3)通过模Y查下表得到对应的校验码:
模值Y 0 1 2 3 4 5 6 7 8 9 10
校验码 1 0 X 9 8 7 6 5 4 3 2
18位SFZ号码的正则表达式如下:
^\d{17}[\d|X]?$
如果不想使用转义字符,就写成以下形式:
^[0-9]{17}[0-9|X]?$
注:15位SFZ号码比较简单,这里就不描述了
2、SFZ号码有效性验证封装类
根据SFZ号码的验证规则,博主将其封装成一个C++通用类,只需传入SFZ号码,便可根据该类轻易的判断出SFZ号码是否有效,代码如下:
1)idnumverify.h
#ifndef IDNUMVERIFY_H
#define IDNUMVERIFY_H
#include <string>
using std::string;
const int kNumLength = 17; // 数字本体码长度
const int kIdNumLength = 18; // SFZ号码长度
// 加权因子
const int kWeightFactor[kNumLength] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
class IdNumVerify
{
public:
IdNumVerify(const string &strIDNum);
int weightedSum();
char checkCode();
bool isValid();
private:
string _strIDNum;
};
#endif // IDNUMVERIFY_H
2)idnumverify.cpp
#include "idnumverify.h"
IdNumVerify::IdNumVerify(const string &strIDNum)
: _strIDNum((strIDNum))
{
}
int IdNumVerify::weightedSum()
{
int sum = 0;
if (_strIDNum.length() >= kNumLength) {
for (int i = 0; i < kNumLength; ++i) {
sum += (_strIDNum[i] - '0') * kWeightFactor[i];
}
}
return sum;
}
char IdNumVerify::checkCode()
{
int k = weightedSum() % 11;
if (k == 0)
return '1';
else if (k == 1)
return '0';
else if (k == 2)
return 'X';
else
return '0'+12-k;
}
bool IdNumVerify::isValid()
{
bool bRet = false;
if (_strIDNum.length() == kIdNumLength) {
if (checkCode() == _strIDNum[kIdNumLength - 1]) {
bRet = true;
} else {
bRet = false;
}
}
return bRet;
}
3、测试Demo
博主使用Qt验证该类的准确性,主要代码如下:
1)对话框头文件
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
void init();
private slots:
void onVerifyClicked();
void onClearClicked();
private:
QLabel *_lblIdNum;
QLineEdit *_edtIdNum;
QLabel *_lblEffective;
QLineEdit *_edtEffective;
QPushButton *_btnVerify;
QPushButton *_btnClear;
QPushButton *_btnExit;
};
#endif // DIALOG_H
2)对话框源文件
#include "dialog.h"
#include "idnumverify.h"
#include <QGridLayout>
#include <QRegExpValidator>
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
init();
}
Dialog::~Dialog()
{
}
void Dialog::init()
{
_lblIdNum = new QLabel(tr("身份证号:"));
_edtIdNum = new QLineEdit;
_edtIdNum->setFixedWidth(220);
_edtIdNum->setFixedWidth(220);
QRegExp regExp(tr("^[0-9]{17}[0-9|X]?$"));
QRegExpValidator *pRegExpValid = new QRegExpValidator(regExp, this);
_edtIdNum->setValidator(pRegExpValid);
_lblEffective = new QLabel(tr("是否有效?"));
_edtEffective = new QLineEdit;
_edtEffective->setReadOnly(true);
_btnVerify = new QPushButton(tr("验证"));
_btnClear = new QPushButton(tr("清空"));
_btnExit = new QPushButton(tr("退出"));
_btnVerify->setFixedSize(QSize(90, 36));
_btnClear->setFixedSize(QSize(90, 36));
_btnExit->setFixedSize(QSize(90, 36));
QFont ft(tr("宋体"), 14);
_lblIdNum->setFont(ft);
_edtIdNum->setFont(ft);
_lblEffective->setFont(ft);
_edtEffective->setFont(ft);
_btnVerify->setFont(ft);
_btnClear->setFont(ft);
_btnExit->setFont(ft);
connect(_btnVerify, SIGNAL(clicked()), this, SLOT(onVerifyClicked()));
connect(_btnClear, SIGNAL(clicked()), this, SLOT(onClearClicked()));
connect(_btnExit, SIGNAL(clicked()), this, SLOT(close()));
QGridLayout* gridLay = new QGridLayout(this);
gridLay->setMargin(16);
gridLay->setSpacing(16);
gridLay->addWidget(_lblIdNum, 0, 0);
gridLay->addWidget(_edtIdNum, 0, 1, 1, 2);
gridLay->addWidget(_lblEffective, 1, 0);
gridLay->addWidget(_edtEffective, 1, 1, 1, 2);
gridLay->addWidget(_btnVerify, 2, 0);
gridLay->addWidget(_btnClear, 2, 1);
gridLay->addWidget(_btnExit, 2, 2);
}
void Dialog::onVerifyClicked()
{
std::string strIdNum = _edtIdNum->text().toStdString();
IdNumVerify objVerify(strIdNum);
if (objVerify.isValid()) {
_edtEffective->setText(tr("^○^ 身份证号有效!"));
} else {
_edtEffective->setText(tr("ˇ‸ˇ 身份证号无效!"));
}
}
void Dialog::onClearClicked()
{
_edtIdNum->clear();
_edtEffective->clear();
}
3)验证结果
本文篇幅较长,SFZ的生成规则及代码在下一篇博文中介绍。