C++:18位SFZ号码有效性验证

12 篇文章 0 订阅

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的生成规则及代码在下一篇博文中介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宏笋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值