ITPub博客

首页 > 数字化转型 > ERP > 校验身份证、组织机构代码证、纳税人识别号、营业执照号 的方法

校验身份证、组织机构代码证、纳税人识别号、营业执照号 的方法

原创 ERP 作者:niuchao 时间:2019-03-26 17:24:06 0 删除 编辑
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/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2004-11-04

  • 博文量
    141
  • 访问量
    136197