طریقه بررسی صحت کدملی به کمک متدهای الحاقی
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: یک دقیقه

برای بررسی صحت کدملی باید کمی با ساختار این کد آشنا شویم. کد ملی 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));
                }

  • #
    ‫۱۱ سال و ۶ ماه قبل، سه‌شنبه ۶ فروردین ۱۳۹۲، ساعت ۲۳:۴۲
    سلام برای بررسی کد ملی من از یک الگوریتم دیگه استفاده کردم توی این پست
  • #
    ‫۱۱ سال و ۶ ماه قبل، چهارشنبه ۷ فروردین ۱۳۹۲، ساعت ۰۹:۵۷
    سلام 
    من متوجه دلیل استفاده از متدهای الحاقی برای بررسی صحت کد ملی ( جایی دیگه هم بررسی صحت ایمیل را دیده بودم )نمیشم . چون به نظر من البته اگه درست باشه با فلفسه وجودی متدهای الحاقی جور در نمیاد . صرف اینکه کد ملی را از نوع 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 را تنها نگه داشت.
  • #
    ‫۱۱ سال و ۶ ماه قبل، سه‌شنبه ۱۳ فروردین ۱۳۹۲، ساعت ۰۶:۲۰
    با سلام الگوریتم طراحی شده با 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 معتبر است؟
      • #
        ‫۱۱ سال و ۶ ماه قبل، پنجشنبه ۱۵ فروردین ۱۳۹۲، ساعت ۰۱:۱۶
        بله از صحت کد ملی 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
        از این دست می‌توانم تعداد بسیاری را مثال بزنم