function ValidatePID(const APID: string): string;
{内部函数,取身份证号校验位,最后一位,对18位有效}
function GetVerifyBit(sIdentityNum: string): Char;
var nNum: Integer;
begin
Result := #0;
nNum := StrToInt(sIdentityNum[1]) * 7 +
StrToInt(sIdentityNum[2]) * 9 +
StrToInt(sIdentityNum[3]) * 10 +
StrToInt(sIdentityNum[4]) * 5 +
StrToInt(sIdentityNum[5]) * 8 +
StrToInt(sIdentityNum[6]) * 4 +
StrToInt(sIdentityNum[7]) * 2 +
StrToInt(sIdentityNum[8]) * 1 +
StrToInt(sIdentityNum[9]) * 6 +
StrToInt(sIdentityNum[10]) * 3 +
StrToInt(sIdentityNum[11]) * 7 +
StrToInt(sIdentityNum[12]) * 9 +
StrToInt(sIdentityNum[13]) * 10 +
StrToInt(sIdentityNum[14]) * 5 +
StrToInt(sIdentityNum[15]) * 8 +
StrToInt(sIdentityNum[16]) * 4 +
StrToInt(sIdentityNum[17]) * 2;
nNum := nNum mod 11;
case nNum of
0: Result := '1';
1: Result := '0';
2: Result := 'X';
3: Result := '9';
4: Result := '8';
5: Result := '7';
6: Result := '6';
7: Result := '5';
8: Result := '4';
9: Result := '3';
10:Result := '2';
end;
end;
var
L,iCentury,iMonth,iDate: Integer;
sCentury,sYear2Bit,sMonth,sDate : string;
CRCFact: string;//18位证号的实际值
CRCTh: string; //18位证号的理论值
FebDayAmt: Byte;//2月天数
begin
L := Length(APID);
if (L in [15, 18]) = False then
begin
Result := Format('身份证号不是15位或18位(%0:s, 实际位数:%1:d)', [APID, L]);
Exit;
end;
CRCFact := '';
if L = 18 then
begin
sCentury := Copy(APID, 7, 2);
iCentury := StrToInt(sCentury);
if (iCentury in [18..20]) = False then
begin
Result := Format('身份证号码无效:18位证号的年份前两位必须在18-20之间(%0:S)', [sCentury]);
Exit;
end;
sYear2Bit := Copy(APID, 9, 2);
sMonth := Copy(APID, 11, 2);
sDate := Copy(APID, 13, 2);
CRCFact := Copy(APID, 18, 1);
end else
begin
sCentury := '19';
sYear2Bit:= Copy(APID, 7, 2);
sMonth := Copy(APID, 9, 2);
sDate := Copy(APID, 11,2);
end;
iMonth := StrToInt(sMonth);
iDate := StrToInt(sDate);
if (iMonth in [01..12]) = False then
begin
Result := Format('身份证号码无效:月份必须在01-12之间(%0:s)', [sMonth]);
Exit;
end;
if (iMonth in [1, 3, 5, 7, 8, 10, 12]) then
begin
if (iDate in [01..31]) = False then
begin
Result := Format('身份证号码无效:日期无效,不能为零或超出当月最大值(%0:s)', [sDate]);
Exit;
end;
end;
if (iMonth in [4, 6, 9, 11]) then
begin
if (iDate in [01..30]) = False then
begin
Result := Format('身份证号码无效:日期无效,不能为零或超出当月最大值(%0:s)', [sDate]);
Exit;
end;
end;
if IsLeapYear(StrToInt(sCentury + sYear2Bit)) = True then
begin
FebDayAmt := 29;
end else
begin
FebDayAmt := 28;
end;
if (iMonth in [2]) then
begin
if (iDate in [01..FebDayAmt]) = False then
begin
Result := Format('身份证号码无效:日期无效,不能为零或超出当月最大值(%0:s)', [sDate]);
Exit;
end;
end;
if CRCFact <> '' then
begin
CRCTh := GetVerifyBit(APID);
if CRCFact <> CRCTh then
begin
Result := Format('身份证号码无效:校验位(第18位)错:(%0:s)', [APID]);
Exit;
end;
end;
end;
//http://wenku.baidu.com/view/71e4eef804a1b0717fd5dd0a.html 参考资料
function GetOrgVerifyBit(sIdentityNum: string): Char;
function GetKeyASC(Key: Char): Integer;
begin
Result := 0;
if ord(Key)<65 then //ASC大于65的是A..Z
Result := strtoint(Key)
else
Result := ord(Key)-55;
end;
var nNum: Integer;
begin
Result := #0;
nNum := GetKeyASC(sIdentityNum[1]) * 3 +
GetKeyASC(sIdentityNum[2]) * 7 +
GetKeyASC(sIdentityNum[3]) * 9 +
GetKeyASC(sIdentityNum[4]) * 10+
GetKeyASC(sIdentityNum[5]) * 5 +
GetKeyASC(sIdentityNum[6]) * 8 +
GetKeyASC(sIdentityNum[7]) * 4 +
GetKeyASC(sIdentityNum[8]) * 2;
nNum := 11-(nNum mod 11);
if nNum = 10 then
Result := 'X'
else if nNum = 11 then
Result := '0'
else
Result := char(nNum+48);
end;
function ValidateSBH(const NSRSBH: string): string;
begin
Result := '';
if not (Length(Trim(NSRSBH)) in [15,16,17,18,19,20]) then
begin
Result := '纳税人识别号位数错误。';
Exit;
end;
if (Copy(NSRSBH,1,1)>='1') and (Copy(NSRSBH,1,1)<='9') then //当身份证号码,包含5开头纳税人识别号
begin
if Length(NSRSBH)=15 then
begin
if GetOrgVerifyBit(Copy(NSRSBH,7,8))<>Copy(NSRSBH,15,1) then //先检验机构代码,检验不过再当老身份证号检验
begin
if Trim(ValidatePID(NSRSBH))<>'' then
begin
Result := '纳税人识别号错误。';
Exit;
end;
end;
end
else if Length(NSRSBH)=18 then //只检验身份证号
begin
if Trim(ValidatePID(NSRSBH))<>'' then
begin
Result := '纳税人识别号错误。';
Exit;
end;
end
else //长度是17,20的就去掉后两位流水号再检验身份证号
begin
if Trim(ValidatePID(Copy(NSRSBH,1,Length(NSRSBH)-2)))<>'' then
begin
Result := '纳税人识别号错误。';
Exit;
end;
end;
end
else if (Copy(NSRSBH,1,1)='L') then //临时发生纳税义务办理临时登记的纳税人
begin
if Trim(ValidatePID(Copy(NSRSBH,2,Length(NSRSBH))))<>'' then
begin
Result := '临时性纳税人识别号错误。';
Exit;
end;
end
else if (Copy(NSRSBH,1,1)='F') or (Copy(NSRSBH,1,1)='J') then //F: 无常设机构的非居民企业的纳税人识别号, J: 以军官证、士兵证
begin
if Length(Trim(NSRSBH))<>15 then
begin
Result := '无常设机构的纳税人识别号位数错误。';
Exit;
end;
if (Copy(NSRSBH,2,14)='00000000000000') or
(Copy(NSRSBH,2,14)='11111111111111') or
(Copy(NSRSBH,2,14)='22222222222222') or
(Copy(NSRSBH,2,14)='33333333333333') or
(Copy(NSRSBH,2,14)='44444444444444') or
(Copy(NSRSBH,2,14)='55555555555555') or
(Copy(NSRSBH,2,14)='66666666666666') or
(Copy(NSRSBH,2,14)='77777777777777') or
(Copy(NSRSBH,2,14)='88888888888888') or
(Copy(NSRSBH,2,14)='99999999999999') then
begin
Result := '无常设机构的纳税人识别号错误。';
Exit;
end;
end
else
begin //其他字母开头表示港、澳、台及外国人,在地区拉丁字母码”首位字母 “4位年份码(登记年份)”只检验年份
try
if (StrToInt(Copy(NSRSBH,2,4))<1990) or (StrToInt(Copy(NSRSBH,2,4))>2050) then
begin
Result := '自然人登记的纳税人识别号错误。';
Exit;
end;
except
Result := '自然人登记的纳税人识别号错误。';
Exit;
end;
end;
end;
function ValidateYYZZH(const YYZZH: string): string;
var i:integer;
CharOK:Boolean;
S: Array [0..14] Of Integer;
P: Array [0..14] Of Integer;
A: Array [0..14] Of Integer;
const M=10;
begin
P[0] := M;
Result := '';
if Length(Trim(YYZZH)) <> 15 then
begin
Result := '营业执照号码位数错误。';
Exit;
end;
CharOK := True;
for i := 1 to 15 do
begin
if not (YYZZH[i] in ['0'..'9']) then
begin
CharOK := False;
Result := '营业执照号码必须为数字。';
Break;
end;
end;
if not CharOK then Exit;
for i := 0 to 14 do
begin
A[i] := StrToInt(YYZZH[i+1]);
S[i] := (P[i] mod (M+1)) + A[i];
if (S[i] mod M = 0) then
P[i+1] := 10*2
else
P[i+1] := (S[i] mod M)*2;
end;
if (S[14] MOD M <> 1) then
begin
Result := '营业执照号码检验错误。';
Exit;
end;
end;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/166523/viewspace-1434280/
,如需转载,请注明出处,否则将追究法律责任。