📄 f_idcard.pas
字号:
////////////////////////////////////////////////////////////////////////////////
// //
// 单元用途:身份证号码相关处理 //
// 单元作者:池龙 //
// 电子邮件:poolord@2ndhometown.net //
// 个人主页:http://www.2ndhometown.net //
// 开发平台:MS Windows 2000 Profrssional / Delphi 6 //
// 最后更新:2005.01.16 //
// //
////////////////////////////////////////////////////////////////////////////////
// //
// 许 可: //
// //
// 您可以不受任何限制的使用、修改、分发这个单元,但请不要删除此说明。 //
// //
// 作者对本单元不作任何显式或隐含的安全性和适用性的担保。 //
// //
// 如果您对本单元进行了修改,请花几分钟发送一份拷贝给我,非常感谢。 //
// //
////////////////////////////////////////////////////////////////////////////////
// //
// 版本历史: //
// //
// 2005.01.16 完成本单元 //
// 基本功能: 1. 从身份证号码中取信息 //
// 2. 判断身份证号码的有效性 //
// 3. 将15位号码转换成18位号码 //
// //
////////////////////////////////////////////////////////////////////////////////
// //
// 备 注: //
// //
// 区划代码转换为名称的部分,需要从外部文件中读取区划定义的数据(如随单 //
// 元发布的文件 regioncode.dat )。 //
// //
// 该文件为纯文本文件,每行是一个代码和名称的对应关系。代码和名称之间以 //
// 逗号作分隔。以#开头的行作为注释行,空行不处理。程序中作了一定的容错处理, //
// 通常情况下,不正确的数据会被略过。但在重新编排时,还是请尽量保证数据的正 //
// 确性。 //
// //
// 另外,为了保证查找的效率,所以要求文件中的记录按区划代码由小到大的顺 //
// 序排列。 //
// //
////////////////////////////////////////////////////////////////////////////////
unit f_IDCard;
interface
uses
Controls,
Classes,
SysUtils;
type
//性别
TSex = (sexUnknown, //未知
sexMale, //男性
sexFemale); //女性
//身份证号码的类型
TIDNumType = (idnum15, //15位
idnum18); //18位
//校验结果
TChecksumRst = (csNoChecksum, //无校验(15位)
csChecksumError, //错误
csChecksumCorrect); //正确
//个人信息
TIDNumInfo = record
IDNumType : TIDNumType; //身份证号码类型
RegionCode : string; //区划代码
RegionStr : string; //区划名称
BirthDay : TDate; //生日
Sex : TSex; //性别
ChecksumRst : TChecksumRst; //校验结果
end;
//区划代码对应关系
TRegionCodeTransRec = record
RegionCode: string; //代码
RegionStr : string; //名称
end;
TRegionCodeTransArray = array of TRegionCodeTransRec;
//分离过的区域代码
TSepRegionCode = record
ProvinceCode : string; //省级代码
CityCode : string; //市级代码
CountyCode : string; //区县级代码
end;
TStrArray = array of string;
const
//18位身份证号码的校验方式中使用的常量
//从左向右,除了末尾的校验位之外,每位的权值
cPosPowerArray : array[1..17] of integer = (7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
//得到的校验值对应的第18位字符
cCheckSumValueArray : array[0..10] of char = ('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
//取身份证号码中的信息
//为了加快速度,不将区划代码进行转换
//需要取得确切的区划名称,用GetRegionStr函数
function GetIDNumInfo(IDNum: string; var IDNumInfo: TIDNumInfo): boolean;
//检查身份证号码的有效性
//内部仍然是利用GetIDNumInfo函数
function IsIDNumValid(IDNum: string): boolean;
//将15位身份证号码扩展为18位
function ExpandIDNum(IDNum15: string; var IDNum18: string): boolean;
//根据区划代码取相应的字符串
function GetRegionStr(RegionCode: string; FromFileName: string): string; overload;
function GetRegionStr(RegionCode: string): string; overload;
function GetRegionStr(var IDNumInfo: TIDNumInfo; FromFileName: string): boolean; overload;
function GetRegionStr(var IDNumInfo: TIDNumInfo): boolean; overload;
//从文件中区划代码信息
function LoadRegionDat(FromFileName: string; var RegionCodeArray: TRegionCodeTransArray): boolean; overload;
//下面这个函数的作用是直接将区划代码信息读入到本单元的公用变量里
function LoadRegionDat(FromFileName: string): boolean; overload;
implementation
var
RegionCodeTransArray : TRegionCodeTransArray;
//判断这个字符是否为数字
function IsDigiChar(TestChar: Char): boolean;
begin
//直接判断文字
Result := TestChar in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
//当然这里也可以使用判断字符ASCII值所在区间的方法,如:
// Result := ord(TestChar) in [ord('0')..ord('9')];
end;
//判断一个字符串是否全部由数字组成
function IsDigiStr(TestStr: string): boolean;
var
Count0 : integer;
begin
if Length(TestStr) > 0 then
begin
Result := true;
for Count0 := 1 to Length(TestStr) do
if not IsDigiChar(TestStr[Count0]) then
begin
Result := false;
Break;
end;
end else
Result := false;
end;
//用于生成18位身份证号码中的校验字符
//注意:此函数不检查前17位的有效性以及其是否为数字
function GenIDNumCheckSumChar(IDNum18: string): char;
var
DataSum : integer;
Count0 : integer;
begin
if length(IDNum18) = 18 then
begin
DataSum := 0;
//将前17位上的各个数字加权累加
for Count0 := 1 to 17 do
Inc(DataSum, StrtoInt(IDNum18[Count0]) * cPosPowerArray[Count0]);
//结果取模,再从字典中得到对应的字符
Result := cCheckSumValueArray[DataSum mod 11];
end else
Result := ' ';
end;
//将15位身份证号码扩展为18位
function ExpandIDNum(IDNum15: string; var IDNum18: string): boolean;
var
IDNumInfo: TIDNumInfo;
TmpIDNum : string;
begin
Result := false;
IDNum18 := '';
//先检察原有的号码是否正确
if (length(IDNum15) = 15) and GetIDNumInfo(IDNum15, IDNumInfo) then
begin
//行政区划代码 + 生日 + 顺序码 + 校验
TmpIDNum := IDNumInfo.RegionCode + formatdatetime('yyyymmdd', IDNumInfo.BirthDay) + Copy(IDNum15, 13, 3) + ' ';
//生成校验码,补到末位
TmpIDNum[18] := GenIDNumCheckSumChar(TmpIDNum);
IDNum18 := TmpIDNum;
Result := true;
end;
end;
function GetIDNumInfo(IDNum: string; var IDNumInfo: TIDNumInfo): boolean;
var
ToProcess : boolean;
IDNumLen,
Year, Month, Day : word;
SexMark : char;
begin
Result := false;
FillChar(IDNumInfo, sizeof(IDNumInfo), #0);
IDNumLen := length(IDNum);
if IDNumLen in [15, 18] then
begin
ToProcess := false;
//检查字符串是否符合要求
case IDNumLen of
//15位身份证号码,全部要求为数字
15 : begin
ToProcess := IsDigiStr(IDNum);
IDNumInfo.IDNumType := idnum15;
IDNumInfo.ChecksumRst := csNoChecksum;
end;
//18位身份证号码,前17位必须是数字,最后一位除数字外,可能是"X"
18 : begin
ToProcess := IsDigiStr(Copy(IDNum, 1, 17)) and (IsDigiChar(IDNum[18]) or (IDNum[18] in ['x', 'X']));
IDNumInfo.IDNumType := idnum18;
end;
end;
if ToProcess then
begin
//取区划代码
IDNumInfo.RegionCode := Copy(IDNum, 1, 6);
//取生日信息
case IDNumInfo.IDNumType of
idnum15 : begin
Year := strtoint('19' + Copy(IDNum, 7, 2));
Month := strtoint(Copy(IDNum, 9, 2));
Day := strtoint(Copy(IDNum, 11, 2));
end;
idnum18 : begin
Year := strtoint(Copy(IDNum, 7, 4));
Month := strtoint(Copy(IDNum, 11, 2));
Day := strtoint(Copy(IDNum, 13, 2));
end;
else
begin
Year := 0;
Month := 0;
Day := 0;
end;
end;
//尝试将生日信息转换成日期
try
IDNumInfo.BirthDay := EncodeDate(Year, Month, Day);
except
ToProcess := false;
end;
if ToProcess then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -