//取身份证号码中的信息 //为了加快速度,不将区划代码进行转换 //需要取得确切的区划名称,用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) > 0then begin Result := true; for Count0 := 1to Length(TestStr) do ifnot IsDigiChar(TestStr[Count0]) then begin Result := false; Break; end; endelse Result := false; end;
//用于生成18位身份证号码中的校验字符 //注意:此函数不检查前17位的有效性以及其是否为数字 function GenIDNumCheckSumChar(IDNum18: string): char; var DataSum : integer; Count0 : integer; begin if length(IDNum18) = 18then begin DataSum := 0; //将前17位上的各个数字加权累加 for Count0 := 1to17do Inc(DataSum, StrtoInt(IDNum18[Count0]) * cPosPowerArray[Count0]); //结果取模,再从字典中得到对应的字符 Result := cCheckSumValueArray[DataSum mod11]; endelse 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 begin //取性别 SexMark := '1'; //取性别标志 case IDNumInfo.IDNumType of idnum15 : SexMark := IDNum[15]; idnum18 : SexMark := IDNum[17]; end; //判断性别 case strtoint(SexMark) mod2of 0 : IDNumInfo.Sex := sexFemale; 1 : IDNumInfo.Sex := sexMale; end;
//如果是18位的身份证,判断校验是否正确 if IDNumInfo.IDNumType = idnum18 then begin if CompareText(GenIDNumCheckSumChar(IDNum), IDNum[18]) = 0then begin IDNumInfo.ChecksumRst := csChecksumCorrect; Result := true; end; endelse Result := true; end; end; end; end;
//判断身份证号码是否正确,通过从中取信息是否成功来判定。 function IsIDNumValid(IDNum: string): boolean; var TmpIDNumInfo : TIDNumInfo; begin Result := GetIDNumInfo(IDNum, TmpIDNumInfo); end;
//将区划代码转换成名称 function RegionCode2Str(RegionCode: string; RegionCodeArray: TRegionCodeTransArray): string;
//在列表中搜索指定的区划代码所对应的名称 //用折半查找,所以要求输入的对应关系必须是有序的 function SearchRegionStr(SearchRegionCode: string): string; var SearchFrom, SearchTo, CheckIdx, SearchValue, CheckValue : integer; begin Result := '';
SearchFrom := low(RegionCodeArray); SearchTo := high(RegionCodeArray); SearchValue := StrToInt(SearchRegionCode); while SearchFrom <= SearchTo do begin CheckIdx := (SearchFrom + SearchTo) div2; CheckValue := StrToInt(RegionCodeArray[CheckIdx].RegionCode);
if CheckValue = SearchValue then begin Result := RegionCodeArray[CheckIdx].RegionStr; Break; endelse if CheckValue > SearchValue then begin SearchTo := CheckIdx - 1; endelse if CheckValue < SearchValue then begin SearchFrom := CheckIdx + 1; end; end; end;
var SepRegionCode : TSepRegionCode; TmpStr, SearchRst : string; begin Result := ''; //区划代码为6位 if (length(RegionCode) = 6) and IsDigiStr(RegionCode) and (length(RegionCodeArray) > 0) then begin //分解区划代码 SepRegionCode.ProvinceCode := Copy(RegionCode, 1, 2); SepRegionCode.CityCode := Copy(RegionCode, 3, 2); SepRegionCode.CountyCode := Copy(RegionCode, 5, 2);
//省级的区划代码不包括11以下的组合 if StrToInt(SepRegionCode.ProvinceCode) > 10then begin //列表内搜索省的名称 TmpStr := ''; SearchRst := SearchRegionStr(SepRegionCode.ProvinceCode + '0000'); if length(SearchRst) > 0then begin TmpStr := SearchRst; //在列表内搜索市的名称 SearchRst := SearchRegionStr(SepRegionCode.ProvinceCode + SepRegionCode.CityCode + '00'); if length(SearchRst) > 0then begin ifnot((SearchRst = '市辖区') or (SearchRst = '县')) then TmpStr := TmpStr + SearchRst; //在列表内搜索县的名称 SearchRst := SearchRegionStr(SepRegionCode.ProvinceCode + SepRegionCode.CityCode + SepRegionCode.CountyCode); if length(SearchRst) > 0then begin ifnot((SearchRst = '市辖区') or (SearchRst = '县')) then TmpStr := TmpStr + SearchRst; end; end; end;
Result := TmpStr; end;
end;
end;
//取区划名称 function GetRegionStr(RegionCode: string; FromFileName: string): string; var RegionCodeArray: TRegionCodeTransArray; begin if LoadRegionDat(FromFileName, RegionCodeArray) then Result := RegionCode2Str(RegionCode, RegionCodeArray) else Result := ''; end;
//取区划名称 function GetRegionStr(RegionCode: string): string; begin Result := RegionCode2Str(RegionCode, RegionCodeTransArray); end;
//取区划名称 function GetRegionStr(var IDNumInfo: TIDNumInfo; FromFileName: string): boolean; var RegionStr : string; begin RegionStr := GetRegionStr(IDNumInfo.RegionCode, FromFileName); ifnot (RegionStr = '') then begin IDNumInfo.RegionStr := RegionStr; Result := true; endelse Result := false; end;
//取区划名称 function GetRegionStr(var IDNumInfo: TIDNumInfo): boolean; var RegionStr : string; begin RegionStr := GetRegionStr(IDNumInfo.RegionCode); ifnot (RegionStr = '') then begin IDNumInfo.RegionStr := RegionStr; Result := true; endelse Result := false; end;
//根据指定分隔符分解字符串,并存入数组 function DecodeStr2Array(Source: string; SepChar: char; var Rst: TStrArray): integer; var Count, CutFrom, Len: word;
procedure AddStr(Str: string); begin SetLength(Rst, length(Rst) + 1); Rst[high(Rst)] := Str; end; begin Result := 0; SetLength(Rst, 0); len := length(Source); if len > 0then begin CutFrom := 1;
for count := 1to len do//逐字符扫描字符串,遇到分隔符时则切断串获得数据 if (Source[count] = SepChar) thenbegin AddStr(Copy(Source, CutFrom, count - CutFrom)); CutFrom := count + 1; if Count = Len then AddStr(''); endelse if count = len then begin AddStr(Copy(Source, CutFrom, count - CutFrom + 1)); Break; end;
Result := length(Rst); end; end;
//把区划代码和名称的对应关系从文件读到变量中 function LoadRegionDat(FromFileName: string; var RegionCodeArray: TRegionCodeTransArray): boolean; var Count0 : integer; RegionDatFile : TStringList; StrArray : TStrArray; begin Result := false; SetLength(RegionCodeArray, 0);
if FileExists(FromFileName) then begin RegionDatFile := TStringList.Create; //读入文件 try RegionDatFile.LoadFromFile(FromFileName); except
end; //处理数据 for Count0 := 0to RegionDatFile.Count - 1do //跳过空行 if length(RegionDatFile[Count0]) > 0then begin //跳过以#开头的行(注释行) ifnot (RegionDatFile[Count0][1] = '#') then begin //分解数据 if (DecodeStr2Array(RegionDatFile[Count0], ',', StrArray) = 2) and//以,分隔的两个字段 (length(StrArray[0]) = 6) and//代码长度为6个字符 IsDigiStr(StrArray[0]) and//代码必须全部是数字 (length(StrArray[1]) > 0) then//名称长度必须大于1 begin //增加内容 SetLength(RegionCodeArray, length(RegionCodeArray) + 1); RegionCodeArray[high(RegionCodeArray)].RegionCode := StrArray[0]; RegionCodeArray[high(RegionCodeArray)].RegionStr := StrArray[1]; end; end; end;
Result := length(RegionCodeArray) > 0;
RegionDatFile.Free; end; end;
//直接将区划代码信息读入到本单元的公用变量里 function LoadRegionDat(FromFileName: string): boolean; begin Result := LoadRegionDat(FromFileName, RegionCodeTransArray); end;