عنوان:

‫طریقه بررسی صحت کدملی به کمک متدهای الحاقی


نویسنده: علیرضا اسم‌رام
تاریخ: ۱۳۹۲/۰۱/۰۶ ۱۶:۲۵
آدرس: www.dntips.ir
برای بررسی صحت کدملی باید کمی با ساختار این کد آشنا شویم. کد ملی 6-761161-007 را در نظر بگیرید. همانطور که مشاهده می‌کنید این کد به 3 قسمت تقسیم شده است. قسمت اول که یک عدد 3 رقمی است نشان دهنده محل تولد فرد است. 6 رقم وسط شماره شناسایی فرد و رقم آخر، رقم کنترل است. در حقیقت ساختار 9 رقم اول طبق الگوریتمی قابل بررسی است که خروجی آن الگوریتم همان رقم آخر است. اگر خروجی الگوریتم با رقم کنترل برابر باشد می‌توان گفت کدملی وارد شده معتبر است و در غیر اینصورت کدملی معتبر نخواهد بود.
برای این منظور دو متدالحاقی زیر به پروژه DNT.Extensions اضافه شده است که بدنه آنها به شرح زیر است:
        /// <summary>
        /// Validate IR National Code
        /// </summary>
        /// <param name="nationalcode">National Code</param>
        /// <returns></returns>
        public static bool IsValidNationalCode(this string nationalcode)
        {
            int last;
            return nationalcode.IsValidNationalCode(out last);
        }

        /// <summary>
        /// Validate IR National Code
        /// </summary>
        /// <param name="nationalcode">National Code</param>
        /// <param name="lastNumber">Last Number Of National Code</param>
        /// <returns></returns>
        public static bool IsValidNationalCode(this string nationalcode, out int lastNumber)
        {
            lastNumber = -1;
            if (!nationalcode.IsItNumber()) return false; 
            var array = nationalcode.ToCharArray();
            if (array.Length != 10) return false;
            var j = 10;
            var sum = 0;
            for (var i = 0; i < array.Length - 1; i++)
            {
                sum += Int32.Parse(array[i].ToString(CultureInfo.InvariantCulture)) * j;
                j--;
            }
            var div = sum / 11;
            var r = div * 11;
            var diff = Math.Abs(sum - r);

            if (diff <= 2)
            {
                lastNumber = diff;
                return diff == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
            }
            var temp = Math.Abs(diff - 11);
            lastNumber = temp;
            return temp == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
        }
طریقه استفاده از این متدها نیز به شرح ذیل است:
bool b = "0077611616".IsValidNationalCode();
پی نوشت:
لطفاً بخش نظرات خوانندگان را نیز دنبال کنید.

نظرات

  • مهمان در ۱۳۹۲/۰۱/۰۶ ۱۷:۳۵
    مشخصا برای اینکه متد قابل اطمینان باشد نباید از متد Parse استفاده کرد. به جای آن از TryParse استفاده کنید تا از وقوع exception جلوگیری شود
    • وحید نصیری در ۱۳۹۲/۰۱/۰۶ ۱۷:۴۰
      اون وقت اگر در این بین به مشکل برخورد چطور؟ استثناء اصلا چیز بدی نیست؛ کرش بسیار پدیده مطلوبی است! چون نشان وجود مشکل در سیستم است.
      بجای اینکار بهتر است در همان بدو امر بررسی شود که رشته دریافتی عدد است یا خیر. چون طول رشته زیاد است می‌شود از مثلا Regex استفاده کرد:
      public static bool IsItNumber(this string inputvalue)
      {
        var isnumber = new Regex("[^0-9]");
        return !isnumber.IsMatch(inputvalue);
      }
      • علیرضا اسم‌رام در ۱۳۹۲/۰۱/۰۶ ۱۷:۵۰
        با تشکر از توجه شما،
        یک متد الحاقی با عنوان IsItNumber به پروژه اضافه شد. همچنین متد IsValidNationalCode اصلاح شد.
                public static bool IsValidNationalCode(this string nationalcode, out int lastNumber)
                {
                    lastNumber = -1;
                    if (!nationalcode.IsItNumber()) return false;
                    var array = nationalcode.ToCharArray();
                    if (array.Length != 10) return false;
                    var j = 10;
                    var sum = 0;
                    for (var i = 0; i < array.Length - 1; i++)
                    {
                        sum += Int32.Parse(array[i].ToString(CultureInfo.InvariantCulture)) * j;
                        j--;
                    }
                    var div = sum / 11;
                    var r = div * 11;
                    var diff = Math.Abs(sum - r);
        
                    if (diff <= 2)
                    {
                        lastNumber = diff;
                        return diff == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
                    }
                    var temp = Math.Abs(diff - 11);
                    lastNumber = temp;
                    return temp == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
                }

  • صابر فتح الهی در ۱۳۹۲/۰۱/۰۶ ۱۹:۱۲
    سلام برای بررسی کد ملی من از یک الگوریتم دیگه استفاده کردم توی این پست
  • mehdi_ در ۱۳۹۲/۰۱/۰۷ ۵:۲۷
    سلام 
    من متوجه دلیل استفاده از متدهای الحاقی برای بررسی صحت کد ملی ( جایی دیگه هم بررسی صحت ایمیل را دیده بودم )نمیشم . چون به نظر من البته اگه درست باشه با فلفسه وجودی متدهای الحاقی جور در نمیاد . صرف اینکه کد ملی را از نوع string میگیریم بررسی صحت اون قابلیتی نیست که بخواهیم به دلیل بسته بودن کلاس string به اون اضافه کنیم . چرا که ارزیابی صحت چیزی که منطق حاکم بر اون هیچ ربطی به کلاس  string نداره را نمیتوان بهش افزود . بهتر نیست این نوع بررسیها به یه کلاس یوتیلیتی منتقل بشه . 
    • مهمان در ۱۳۹۲/۰۱/۰۷ ۹:۴۷
      این نوع کلاس‌ها هم تماما کمکی هستند. به همان روش سابق نام کلاس نام متد هم قابل دسترسی‌اند. به علاوه، به این ترتیب، علاوه بر روش قدیمی فراخوانی، حالت فراخوانی fluent هم میسر می‌شود که از دیدگاه زبان انگلیسی خواندنش ساده‌تر است و روان‌تر.
  • مهمان در ۱۳۹۲/۰۱/۰۷ ۱۲:۵۵
    سلام
    جالبه! فقط یه نکته میشه به جای
     var div = sum / 11;
     var r = div * 11;
     var diff = Math.Abs(sum - r);
    نوشت :
    var diff = sum % 11;


    • علیرضا اسم‌رام در ۱۳۹۲/۰۱/۰۷ ۱۳:۲۹
      سلام.
      بله دو دستور فوق معادل یکدیگرند. من قبل از انتشار نسخه نهایی با مقادیر r و div کارهای دیگری انجام داده بودم که با توجه به حذف آن موارد می‌توان باقیمانده تقسیم sum بر 11 را تنها نگه داشت.
  • RezaNBT در ۱۳۹۲/۰۱/۱۳ ۱:۵۰
    با سلام الگوریتم طراحی شده با reminder کمتر یا مساوی 2 مقدار غلط بر میگرداند.بعنوان مثال مقدار محاسبه شده برای کد 0010350829 که معتبر می‌باشد برابر با 2 می‌باشد که باید از دوره تناوب کنترل کننده‌ی نقلی یعنی عدد 11 کم شود. یعنی :
    if (diff <= 2)
        {
            lastNumber = diff;
            return diff ==(11- Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture)));
        }
    به نظر بنده نیازی به چک کردن و شاخه ای کردن کد نمی‌باشد و این بلوک شرطی می‌بایستی حذف گردد و در هر حالتی 11 از رقم نقلی کم شود و با مقدار حساب شده مقایسه شود.

    از طرفی چون این فرمول نقلی به ازای هر عدد ده رقمی دارای تکرار فقط یک رقم  خروجی صحیح دارد می‌بایستی این مورد هم کنترل گردد. یعنی در ابتدای تابع الحاقی باید داشته باشیم:

     var allDigitEqual = new[] { "0000000000", "1111111111", "2222222222", "3333333333", "4444444444", "5555555555", "6666666666", "7777777777", "8888888888", "9999999999" };
                if (allDigitEqual.Contains(nationalcode)) return false;



    • صابر فتح الهی در ۱۳۹۲/۰۱/۱۳ ۳:۵۲
      البته به جای این کد می‌توان  از این هم استفاده کرد که به نظر خواناتر هست.
    • مهمان در ۱۳۹۲/۰۱/۱۳ ۱۲:۲۲
      شما اطمینان دارید که کدملی 0010350829 معتبر است؟
    • علیرضا اسم‌رام در ۱۳۹۲/۰۱/۱۳ ۱۲:۳۳
      با تشکر از شما متد فوق بصورت زیر اصلاح شد و کلاس مربوطه بروزرسانی شده است:
              /// <summary>
              /// Validate IR National Code
              /// </summary>
              /// <param name="nationalcode">National Code</param>
              /// <param name="lastNumber">Last Number Of National Code</param>
              /// <returns></returns>
              public static bool IsValidNationalCode(this string nationalcode, out int lastNumber)
              {
                  lastNumber = -1;
                  if (!nationalcode.IsItNumber()) return false;
                  var invalid = new[]
                                          {
                                              "0000000000", "1111111111", "2222222222", "3333333333", "4444444444", "5555555555",
                                              "6666666666", "7777777777", "8888888888", "9999999999"
                                          };
                  if (invalid.Contains(nationalcode)) return false;
                  var array = nationalcode.ToCharArray();
                  if (array.Length != 10) return false;
                  var j = 10;
                  var sum = 0;
                  for (var i = 0; i < array.Length - 1; i++)
                  {
                      sum += Int32.Parse(array[i].ToString(CultureInfo.InvariantCulture)) * j;
                      j--;
                  }
      
                  var diff = sum % 11;
      
                  if (diff < 2)
                  {
                      lastNumber = diff;
                      return diff == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
                  }
                  var temp = Math.Abs(diff - 11);
                  lastNumber = temp;
                  return temp == Int32.Parse(array[9].ToString(CultureInfo.InvariantCulture));
              }
      البته من فرض کردم که کد ملی 0010350829 معتبر و کد 0010350822 نامعتبر است. آیا شما مطمئن هستید که کد 0010350829 معتبر است؟
      • صابر فتح الهی در ۱۳۹۲/۰۱/۱۴ ۸:۴۸
        سلام
        مهندس این تکه کد توسط آقای ابراهیم بیاگوی بهبود داده شده و به نظر شخصی من بهتره.
      • RezaNBT در ۱۳۹۲/۰۱/۱۴ ۲۰:۴۶
        بله از صحت کد ملی 0010350829 اطمینان کامل دارم. شما هم می‌توانید محض اطمینان با الگوریتم‌های دیگر تست کنید.
        • شهریار در ۱۳۹۲/۰۱/۱۴ ۲۱:۲۷
          با سلام

          من از الگوریتم زیر استفاده میکنم گفتم اینجا بنویسم شاید به کار بیاد

           Private Function ValidateNcode(ByVal NC As Int64) As Boolean
                  If IsNumeric(NC) = False Or NC.ToString.Length < 10 Then
                      Return False
                  End If
                  Dim vnc As String = NC.ToString
                  Dim pos As Integer = 10
                  Dim sum As Integer = 0
          
                  For i = 0 To 8
                      sum += Integer.Parse(vnc.ToCharArray()(i).ToString()) * pos
                      pos = pos - 1
                  Next i
          
                  Dim remind As Integer = sum Mod 11
                  Dim controlNum As Integer = Integer.Parse(vnc.ToCharArray()(9))
          
                  If remind <= 2 Then
                      If controlNum = remind Then
                          Return True
                      Else
                          Return False
                      End If
                  Else
                      If (11 - remind) = controlNum Then
                          Return True
                      Else
                          Return False
                      End If
                  End If
              End Function
          private bool ValidateNcode(Int64 NC)
          {
          if (IsNumeric(NC) == false | NC.ToString.Length < 10) {
          return false;
          }
          string vnc = NC.ToString;
          int pos = 10;
          int sum = 0;
          
          for (i = 0; i <= 8; i++) {
          sum += int.Parse(vnc.ToCharArray()(i).ToString()) * pos;
          pos = pos - 1;
          }
          
          int remind = sum % 11;
          int controlNum = int.Parse(vnc.ToCharArray()(9));
          
          if (remind <= 2) {
          if (controlNum == remind) {
          return true;
          } else {
          return false;
          }
          } else {
          if ((11 - remind) == controlNum) {
          return true;
          } else {
          return false;
          }
          }
  • فرهاد ر در ۱۳۹۲/۰۶/۱۷ ۱۴:۱
    اتباع خارجی هم کد شناسایی دارن.
    آیا میشه متدیم برای تشخیص صحت این کد پیشنهاد بدین.
  • مهمان در ۱۳۹۲/۰۸/۲۷ ۷:۵۹
    یک حالت جدید پیدا کردم که مطمئنا خود ثبت احوال هم نمی‌دونه! هر عدد ده رقمی که به فرم قربنه وارد بشه، صحیح فرض میشه!
    مثلا a00000000a  یا 1234554321 یا 1346886431 همگی صحیح فرض میشن حال آنکه اشتباه هستن! 
    • مهمان در ۱۳۹۲/۰۸/۲۷ ۱۷:۵۱
      من براتون یه کد ملی میارم که کل این الگوریتم رو نقض کنه. کد ملی 1111111111 متعلق به آقایی در شهررضا هست! من چون به تعداد بالایی کد ملی دسترسی دارم، بررسی کردم  و الان مطمئن هستم ثبت احوال در سالهای ابتدایی تخصیص کد ملی، خطا داشته.
      • مهمان در ۱۳۹۳/۰۴/۲۲ ۱:۳۹
        سلام به دوستان عزیز، این الگوریتم برای حدود 10 درصد از کد ملی‌ها درست عمل نمی‌کند به عنوان نمونه کدهای زیر در الگوریتم فوق فاقد اعتبار هستند (از صحت کد ملی اطمینان دارم)
        1381647899
        0922351873
        4122587241
        4312281949
        4220196526
        6219937997
        0077910345
        4569973963
        2133288158
        2003987765
        2758531405
        4251235692
        2156345454
        1222365215
        5412568954
        از این دست می‌توانم تعداد بسیاری را مثال بزنم