# Native Code > برنامه نویسی در Delphi > مباحث عمومی دلفی و پاسکال > آموزش: تشخیص صحت شناسه ملی اشخاص حقوقي

## saeedjaihoni

مطلب زير رو از اين آدرس گرفتم و كد جاوا اسكريپتش هم بصورتي كه مي بينيد بود و من لازم ديدم كه اونو براي دوستاني كه به اين كد نياز دارن به كد دلفي تبديل كنم
لينك منبع : http://www.aliarash.com/article/shen...enasa_meli.htm

امروزه در اکثر نرم افزارهای تولیدی نیاز به استفاده از شناسه ملی اشخصاص حقوقی به عنوان یک مشخصه منحصر به فرد برای اطلاعات شخص حقوقي می باشد.
برای استعلام شناسه ملی می توانید به سایت http://www.ilenc.ir مراجعه نموده و با وارد کردن مشخصات شخص حقوقی مورد نظر اقدام به جستجوی شناسه ملی داده شده نمایید. نتیجه این جستجو محل ثبت ، نام شخص حقوقی، شماره ثبت ، شناسه ملی ، تاریخ ثبت و آدرس و کد پستی شخص حقوقی می باشد
هر چند روش بالا برای اطمینان از صحت و ارتباط شناسه داده شده با شخص مورد نظر روش خوبی است ولی همواره نیازمند داشتن یک اتصال اینترنتی بوده و به صورت موردی باید جستجو شود. (شبیه بررسی مدارک در مراحل اولیه کارها ) اما مهندسان نرم افزار و برنامه نویسان نیازمند يک الگوی کنترلی برای صحت کد می باشند تا بتوانند از ورود کد های نامعتبر جلوگیری کرده  و یا کد های موجود در سیستم را وارسی نمایند.
متاسفانه در حال حاضر هیچ الگوریتمی برای تشخیص صحت کد ورودی در اختیار برنامه نویسان وجود ندارد.
اخیرا با توجه به نیاز خودم به کنترل صحت کد ورودی ،الگوریتم مربوط به کنترل صحت شناسه ملی را بدست آوردم و چون مطمئن هستم افراد زیادی هم همین نیاز را دارند روال انجام کار را در این جا توضیح می دهم
شناسه ملی شماره ای است 11 رقمی که از سمت چپ چهار رقم کد شهرستان محل ثبت ، شش رقم بعدی کد منحصر به فرد برای شخص حقوقی دارنده شناسه در شهرستان محل ثبت و رقم آخر آن هم یک رقم کنترل است که از روی 10 رقم سمت چپ بدست می آید. برای بررسی کنترل کد کافی است مجدد از روی 10 رقم سمت چپ رقم کنترل را محاسبه کنیم
 ساختار شناسه ملی در زیر نشان داده شده است
ساختار شناسه ملی
ارقام کد	رقم کنترل	10 رقم سمت چپ شناسه ملی
موقعیت	
1
2	3	4	5	6	7	8	9	10

1- برای محاسبه رقم کنترل از روی سایر ارقام ، هر رقم را  با رقم دهگان کد +2 کرده و سپس در ضریب آن ضرب می کنیم و حاصل را با هم جمع می کنیم.
2- مجموع بدست آمده از مرحله یک را بر 11 تقسیم می کنیم
3- اگر باقیمانده برابر 10 باشد ، باقیمانده را برابر 0 قرار می دهیم
4-اگر رقم کنترل برابر باقیمانده باشد شناسه ملی صحیح فرض می شود در غیر این صورت شناسه ملی مورد نظر صحیح نمی باشد

مثال : آیا کد 10380284790 یک شناسه ملی معتبر است؟ (نمایش اطلاعات مالک شناسه)
برای این منظور باید براساس جدول زیر عمل کنیم. دقت کنید که ضریب ارقام دهگان به بعد عبارتند از 17 ، 19 ، 23 ، 27، 29 و همین الگو مجددا تکرار شده است
ساختار شناسه ملی
ساختار کد	رقم کنترل	10 رقم سمت چپ شناسه ملی
ارقام شناسه	0	9	7	4	8	2	0	8	3	0	1
رقم دهگان +2	 	11	11	11	11	11	11	11	11	11	11
ضريب ارقام	 	17	19	23	27	29	17	19	23	27	29
محاسبه حاصل ضرب	 	340	342	345	513	377	187	361	322	297	348

هریک از ارقام سمت چپ شناسه ملی (10 رقم سمت چپ شناسه ملی) را با رقم دهگان شناسه ملی +2  جمع می کنیم و حاصل را در  را ضریب آن رقم ضرب کرده و نتیجه ها را با هم جمع می کنیم  .
دقت کنید در اینجا رقم دهگان 9 و رقم دهگان +2 برابر با 11 می باشد. بنابراین همه ارقام کد با 11 جمع شده و سپس در ضریب مربوط به خودش ضرب شده است.
(1+11)*29+(0+11)*27+(3+11)*23+(8+11)*19+(0+11)*17+  (2+11)*29+(8+11)*27+(4+11)*23+(7+11)*19+(9+11)*17=  3432
3432÷11=312 و R=0
چون باقیمانده برابر صفر  است پس باید رقم کنترل این شناسه برابر صفر باشد.
با دقت در شناسه ملی مورد نظر متوجه می شویم که رقم کنترل ورودی برابر صفر است پس شناسه ملی مورد نظر به عنوان یک شناسه ملی معتبر قابل قبول است.


كد جاوا اسكريپت :
function checkCodeMeli(code)
{
  
  var L=code.length;
  
  if(L<11 || parseInt(code,10)==0) return false;
  
  if(parseInt(code.substr(3,6),10)==0) return false;
  var c=parseInt(code.substr(10,1),10);
  var d=parseInt(code.substr(9,1),10)+2;
  var z=new Array(29,27,23,19,17);
  var s=0;
  for(var i=0;i<10;i++)
    s+=(d+parseInt(code.substr(i,1),10))*z[i%5];
  s=s%11;if(s==10) s=0;
  return (c==s);

}


كد دلفي :
function TForm1.ShMeli(Code : String):Boolean;
var L,C,D,S,I : Integer;
    flag : Boolean;
begin

  flag := (Code = '00000000000') or (code = '11111111111') or (code = '22222222222') or (code = '33333333333');
  flag := (Code = '44444444444') or (code = '55555555555') or (code = '66666666666') or (code = '77777777777') or flag;
  flag := (Code = '88888888888') or (code = '99999999999') or flag;
  if not flag then
  begin
   if Code = '' then
     ShMeli:= False
   else
   if Length(Code) < 11 then
     ShMeli := False
   else
   begin
     C:= StrToInt(Code[11]); // شناسايي رقم كنترل
     L:=Length(Code); // محاسبه طول كد
     D:= StrToInt(Code[10])+2;   /// محاسبه دهگان +2

     S := 0;     //1- براي محاسبه رقم کنترل از روي ساير ارقام ، هر رقم را  با رقم
     // دهگان کد +2 کرده و سپس در ضريب آن ضرب مي کنيم و حاصل را با هم جمع مي کنيم.
       S := s + ((d+StrToInt(Code[1]))*29);
       S := s + ((d+StrToInt(Code[2]))*27);
       S := s + ((d+StrToInt(Code[3]))*23);
       S := s + ((d+StrToInt(Code[4]))*19);
       S := s + ((d+StrToInt(Code[5]))*17);
       S := s + ((d+StrToInt(Code[6]))*29);
       S := s + ((d+StrToInt(Code[7]))*27);
       S := s + ((d+StrToInt(Code[8]))*23);
       S := s + ((d+StrToInt(Code[9]))*19);
       S := s + ((d+StrToInt(Code[10]))*17);
       S := s mod 11;            //2- مجموع بدست آمده از مرحله يک را بر 11 تقسيم مي کنيم
     if s = 10 then        //3- اگر باقيمانده برابر 10 باشد ، باقيمانده را برابر 0 قرار مي دهيم
       s := 0
     else
     if s = c then  //4-اگر رقم کنترل برابر باقيمانده باشد شناسه ملي صحيح فرض مي شود
       ShMeli := True;
   end;
  end
  else ShMeli := False;  //در غير اين صورت شناسه ملي مورد نظر صحيح نمي باشد
end;

مثال :
procedure TForm1.Button1Click(Sender: TObject);
begin

if CodeMeli(Edit1.Text)=true then
ShowMessage('.كد صحيح است')
else
ShowMessage('.كد معتبر نيست');


end;

----------


## developing

با سلام

دوستان من این کد رو امتحان کردم درست نبود.

من کوچیک تر از اون هستم که ...
اما از اساتیدی مثل آقا شاهین و داش یوسف انتظار داشتیم قبل از اینکه تشکر کنند (که برای خیلی ها در این تالار به عنوان تایید یک پست به کار می ره) بیشتر دقت کنند.

من کد زیر رو به عنوان تایید کدملی استفاده می کنم که به ازای هر کاری که می خوام نتیجه ی خوبی می ده مثلا اگه تعداد اعداد 10 تا نباشه یا اینکه مشابه باشه تابع مقادیر خاص خودش رو بر می گردونه. 

البته نظرات شما راهنمای کار ما خواهد بود.

function ValidateNationalCode(NationalCode: string): Byte;
const
  Valid = 1;
  NumberNotEqual10 = 2;
  SameNumber = 4;
var
  I, Sum, a, c: Integer;
  First5, Last5, First2, First34: string;
begin
  Result := 0;
  if Length(NationalCode) <> 10 then
    Exit(NumberNotEqual10);
  Last5 := RightStr(NationalCode, 5);
  First5 := LeftStr(NationalCode, 5);
  First2 := LeftStr(First5, 2);
  First34:= RightStr(First5, 2);
  if (First5 = Last5)and(First2 = First34)and(First2[1] = First2[2])
    and(First2[1]= First5[3])then
    Exit(SameNumber);
  Sum := 0;
  for I := 1 to Length(NationalCode) - 1 do
    Sum := Sum + (11 - i) * StrToInt(NationalCode[i]);
  a := StrToInt(NationalCode[10]);
  c := sum mod 11;
  if ((c < 2) and (c = a))or
     ((c >= 2) and (a = 11 - c))then
    Result := Valid;
end;

----------


## Mask

بیش از چندین پست در همین سایت در این مورد وجود داره. لطفا قبلا از ایجاد پست جستجو کنید. و چرخ رو دوباره اختراع نکنید.

----------


## hossein_h62

> با سلام
> 
> دوستان من این کد رو امتحان کردم درست نبود.
> 
> من کوچیک تر از اون هستم که ...
> اما از اساتیدی مثل آقا شاهین و داش یوسف انتظار داشتیم قبل از اینکه تشکر کنند (که برای خیلی ها در این تالار به عنوان تایید یک پست به کار می ره) بیشتر دقت کنند.
> 
> من کد زیر رو به عنوان تایید کدملی استفاده می کنم که به ازای هر کاری که می خوام نتیجه ی خوبی می ده مثلا اگه تعداد اعداد 10 تا نباشه یا اینکه مشابه باشه تابع مقادیر خاص خودش رو بر می گردونه. 
> 
> ...


سلام
مطلبی که دوستمون در پست1 گذاشتند همونطور که از عنوان تاپیک مشخص هست مربوطه به *شناسه ملی اشخاص حقوقی* هست، نه کد ملی اشخاص حقیقی؛ این دو هم ساختار متفاوتی دارن و هم الگوریتم کنترلی متفاوت. کدی که شما (*developing*) گذاشتید مربوط به کد ملی اشخاص حقیقی هست.
در ضمن کد پست 1 رو کنترل کردم فقط یه اصلاح کوچیک میخواد که باید در Line 37 کلمه ELSE به end تغییر پیدا کنه. با یه سری شناسه ملی هم کنترلش کردم مشکل دیگه ای نداشت.
کد نهایی اینجوری میشه :
function TForm1.ShMeli(Code : String):Boolean;
var L,C,D,S,I : Integer;
    flag : Boolean;
begin

  flag := (Code = '00000000000') or (code = '11111111111') or (code = '22222222222') or (code = '33333333333');
  flag := (Code = '44444444444') or (code = '55555555555') or (code = '66666666666') or (code = '77777777777') or flag;
  flag := (Code = '88888888888') or (code = '99999999999') or flag;
  if not flag then
  begin
   if Code = '' then
     ShMeli:= False
   else
   if Length(Code) < 11 then
     ShMeli := False
   else
   begin
     C:= StrToInt(Code[11]); // شناسايي رقم كنترل
     L:=Length(Code); // محاسبه طول كد
     D:= StrToInt(Code[10])+2;   /// محاسبه دهگان +2

     S := 0;     //1- براي محاسبه رقم کنترل از روي ساير ارقام ، هر رقم را  با رقم
     // دهگان کد +2 کرده و سپس در ضريب آن ضرب مي کنيم و حاصل را با هم جمع مي کنيم.
       S := s + ((d+StrToInt(Code[1]))*29);
       S := s + ((d+StrToInt(Code[2]))*27);
       S := s + ((d+StrToInt(Code[3]))*23);
       S := s + ((d+StrToInt(Code[4]))*19);
       S := s + ((d+StrToInt(Code[5]))*17);
       S := s + ((d+StrToInt(Code[6]))*29);
       S := s + ((d+StrToInt(Code[7]))*27);
       S := s + ((d+StrToInt(Code[8]))*23);
       S := s + ((d+StrToInt(Code[9]))*19);
       S := s + ((d+StrToInt(Code[10]))*17);
       S := s mod 11;            //2- مجموع بدست آمده از مرحله يک را بر 11 تقسيم مي کنيم
     if s = 10 then        //3- اگر باقيمانده برابر 10 باشد ، باقيمانده را برابر 0 قرار مي دهيم
       s := 0
     end;
     if s = c then  //4-اگر رقم کنترل برابر باقيمانده باشد شناسه ملي صحيح فرض مي شود
       ShMeli := True;
  end
  else ShMeli := False;  //در غير اين صورت شناسه ملي مورد نظر صحيح نمي باشد
end;

----------


## f.beigirad

کسی میدونه کد شناسایی اتباع رو چجوری اعتبار سنجی کنیم؟

----------


## lightblue

سلام

ضمن تشکر فراوان از *saeedjaihoni* من دیدم زحمت کشیدن برای جاوا اسکریپت و دلفی کد نوشتن من هم برای جاوا کد تشخیص صحت شناسه ملی اشخاص حقوقی و کد ملی اشخاص حقیقی رو باز نویسی کردم:


    public static boolean checkLegalNationalCode(String nationalCode) {

        if (nationalCode.length() < 11 || Integer.parseInt(nationalCode) == 0)
            return false;

        if (Integer.parseInt(nationalCode.substring(3, 9)) == 0)
            return false;
        
        int c = Integer.parseInt(nationalCode.substring(10, 11));
        int d = Integer.parseInt(nationalCode.substring(9, 10)) + 2;
        int[] z = new int[] { 29, 27, 23, 19, 17 };
        int s = 0;
        
        for (byte i = 0; i < 10; i++)
            s += (d + Integer.parseInt(nationalCode.substring(i, i + 1))) * z[i % 5];
        
        s = s % 11;
        
        if (s == 10)
            s = 0;
        
        return (c == s);
    }

    public static boolean checkPersonalNationalCode(String nationalCode) {
        boolean retVal = false;
        float c, n, r;

        if (!(nationalCode.length() < 10 ||
            nationalCode == "0000000000" ||
            nationalCode == "1111111111" ||
            nationalCode == "2222222222" ||
            nationalCode == "3333333333" ||
            nationalCode == "4444444444" ||
            nationalCode == "5555555555" ||
            nationalCode == "6666666666" ||
            nationalCode == "7777777777" ||
            nationalCode == "8888888888" ||
            nationalCode == "9999999999"))
        {
            c = Float.valueOf(nationalCode.substring(9, 10));

            n = Integer.valueOf(nationalCode.substring(0, 1)) * 10 +
                Integer.valueOf(nationalCode.substring(1, 2)) * 9 +
                Integer.valueOf(nationalCode.substring(2, 3)) * 8 +
                Integer.valueOf(nationalCode.substring(3, 4)) * 7 +
                Integer.valueOf(nationalCode.substring(4, 5)) * 6 +
                Integer.valueOf(nationalCode.substring(5, 6)) * 5 +
                Integer.valueOf(nationalCode.substring(6, 7)) * 4 +
                Integer.valueOf(nationalCode.substring(7, 8)) * 3 +
                Integer.valueOf(nationalCode.substring(8, 9)) * 2;

            r = (n - ((int)(n / 11) * 11));

            if ((r == 0 && r == c) || (r == 1 && c == 1) || (r > 1 && c == (11 - r)))
                retVal = true;
        }
        return retVal;
    }

----------


## tazarvmmr

امروز دنبال الگوریتم تشخیص شناسه ملی اشخاص حقوقی بودم که بعد از یکی دو جا که اشتباه گفته بودن درستشو اینجا پیدا کردم و خوشبختانه کد دلفی هم دوستان گذاشته بودن، با اجازتون کد رو برداشتم و استفاده کردم ولی از اونجاییکه قطعا کد برای توضیح نوشته شده صرفا، در نامگذاری ها و طریقه نوشتن خیلی حوصله به خرج داده نشده، من بااجازتون یک مقداری به لحاظ نحوه نوشتن تغییرش دادم و فکر میکنم شاید اینجا قرارش بدم بد نباشه، شاید کسی به دردش خورد :)


function IsThisNICCorrect(NIC: string): boolean;
var
  Len,
  ControlCode,
  Factor,
  Sum,
  Remaining : Integer;
  Flag : Boolean;
begin
  Result := false;
  Len := Length(NIC);
  Flag := (NIC = '00000000000') or (NIC = '11111111111') or (NIC = '22222222222') or (NIC = '33333333333');
  Flag := (NIC = '44444444444') or (NIC = '55555555555') or (NIC = '66666666666') or (NIC = '77777777777') or Flag;
  Flag := (NIC = '88888888888') or (NIC = '99999999999') or Flag;
  if (Flag = true) or (Len < 11) then
    Exit;
  ControlCode := StrToInt(NIC[11]);
  Factor := StrToInt(NIC[10]) + 2;
  Sum := 0;
  Sum := Sum + ((Factor + StrToInt(NIC[1])) * 29);
  Sum := Sum + ((Factor + StrToInt(NIC[2])) * 27);
  Sum := Sum + ((Factor + StrToInt(NIC[3])) * 23);
  Sum := Sum + ((Factor + StrToInt(NIC[4])) * 19);
  Sum := Sum + ((Factor + StrToInt(NIC[5])) * 17);
  Sum := Sum + ((Factor + StrToInt(NIC[6])) * 29);
  Sum := Sum + ((Factor + StrToInt(NIC[7])) * 27);
  Sum := Sum + ((Factor + StrToInt(NIC[8])) * 23);
  Sum := Sum + ((Factor + StrToInt(NIC[9])) * 19);
  Sum := Sum + ((Factor + StrToInt(NIC[10])) * 17);
  Remaining := Sum mod 11;
  if Remaining = 10 then
    Remaining := 0;
  Result := (Remaining = ControlCode);
end;

----------


## shahab_8121

با سلام خدمت تمام اساتید گرامی 
ببخشید ک بعد مدتها دوباره این تاپیک رو دوباره فعال کردم . خطایی تو این روشی ک دوستان ارائه کردن واضح ک یه مثال نقضش این کد نمونه است 12345678910 که تو این الگوریتم به عنوان درست حساب می کنه اما در واقع یک کد غیر معتبر می باشد.
از نظر الگوریتمی صحیح می باشد اما هنوز به عنوان شرکت ثبت نشده است :)

----------


## یوسف زالی

این الگوریتم که به جایی وصل نیست که بیاد ببینه کی چه شرکتی ثبت کرده.منظورتون رو نمی فهمم.

----------

