Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Check Iranian National Code Validity - بررسی صحت کد ملی ایرانی - Clojure, C#, Ruby, JavaScript, Python, Scala, Java 8, PHP, C, Go, Swift, Kotlin, Groovy, Rust, Haskell, Erlang, Elixir
// Check Iranian National Code Validity - Clojure, C#, Ruby, JavaScript, Python, Scala, Java 8, PHP, C, Go, Swift, Kotlin, Groovy, Rust, Haskell, Erlang, Elixir
// بررسی صحت کد ملی ایران - کلوژر، سی‌شارپ، روبی، جاوااسکریپت، پایتون، اسکالا، جاوا ۸، پی‌اچ‌پی، سی، گو، سوئیفت، کاتلین، گرووی، راست، هسکل، ارلنگ، الکسیر
// در نسخه‌های قبل یکسان بودن اعداد نا معتبر تشخیص داده می‌شد ولی
// اعداد یکسان نامعتبر نیست http://www.fardanews.com/fa/news/127747
// بعضی از پیاده‌سازی‌ها سریع نیستند، می‌توانید نسخهٔ خود را بر پایهٔ
// نسخهٔ سی یا گو ایجاد کنید که بهترین سرعت را داشته باشد
/**
* @author Ebrahim Byagowi (2013-)
* @license: Public Domain
*/
// Clojure
(defn valid-iran-code? [input]
(if (re-matches #"^\d{10}$" input)
(let
[check (Integer/parseInt (subs input 9 10))
sum (mod (reduce + (map (fn [x] (* (Integer/parseInt
(subs
input x (+ x 1)))
(- 10 x)))
(range 9))) 11)]
(or (and (< sum 2) (== check sum))
(and (>= sum 2) (== (+ check sum) 11))))
false))
// Ruby
def is_valid_iran_code(input)
return false if /^\d{10}$/ !~ input
check = Integer(input[9])
s = (0..8).map{|x| Integer(input[x]) * (10 - x)}.inject(:+) % 11
(s < 2 && check == s) || (s >= 2 && check + s == 11)
end
// C#
using System.Text.RegularExpressions;
public static bool IsValidIranianNationalCode(string input)
{
if (!Regex.IsMatch(input, @"^\d{10}$"))
return false;
var check = Convert.ToInt32(input.Substring(9, 1));
var sum = Enumerable.Range(0, 9)
.Select(x => Convert.ToInt32(input.Substring(x, 1)) * (10 - x))
.Sum() % 11;
return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
}
// JavaScript
function isValidIranianNationalCode(input) {
if (!/^\d{10}$/.test(input))
return false;
var check = parseInt(input[9]);
var sum = 0;
var i;
for (i = 0; i < 9; ++i) {
sum += parseInt(input[i]) * (10 - i);
}
sum %= 11;
return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
}
// ES6
function isValidIranianNationalCode(input) {
if (!/^\d{10}$/.test(input))
return false;
var check = +input[9];
var sum = Array(9).fill().map((_, i) => +input[i] * (10 - i)).reduce((x, y) => x + y) % 11;
return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
}
// C
bool isValidIranianNationalCode(const char *input) {
for (int i = 0; i < 10; ++i) if (input[i] < '0' || input[i] > '9') return false;
int check = input[9] - '0';
int sum = 0;
for (int i = 0; i < 9; ++i) sum += (int)(input[i] - '0') * (10 - i);
sum %= 11;
return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
}
// Go
func isValidIranianNationalCode(input string) bool {
for i := 0; i < 10; i++ {
if input[i] < '0' || input[i] > '9' {
return false
}
}
check := int(input[9] - '0')
sum := 0
for i := 0; i < 9; i++ {
sum += int(input[i]-'0') * (10 - i)
}
sum %= 11
return (sum < 2 && check == sum) || (sum >= 2 && check+sum == 11)
}
// Python
import re
def is_valid_iran_code(input):
if not re.search(r'^\d{10}$', input):
return False
check = int(input[9])
s = sum([int(input[x]) * (10 - x) for x in range(9)]) % 11
return (s < 2 and check == s) or (s >= 2 and check + s == 11)
// Scala
def isValidIranianNationalCode(input: String) = {
val pattern = """^(\d{10})$""".r
input match {
case pattern(_) =>
val check = input.substring(9, 10).toInt
val sum = (0 to 8)
.map(x => input.substring(x, x + 1).toInt * (10 - x))
.sum % 11
(sum < 2 && check == sum) || (sum >= 2 && check + sum == 11)
case _ => false
}
}
// Java 8
import java.util.stream.Streams;
import java.util.function.IntUnaryOperator;
public static boolean isValidIranianNationalCode(String input) {
if (!input.matches("^\\d{10}$"))
return false;
int check = Integer.parseInt(input.substring(9, 10));
int sum = IntStream.range(0, 9)
.map(x -> Integer.parseInt(input.substring(x, x + 1)) * (10 - x))
.sum() % 11;
return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
}
// PHP
function isValidIranianNationalCode($input) {
# check if input has 10 digits that all of them are not equal
if (!preg_match("/^\d{10}$/", $input)) {
return false;
}
$check = (int) $input[9];
$sum = array_sum(array_map(function ($x) use ($input) {
return ((int) $input[$x]) * (10 - $x);
}, range(0, 8))) % 11;
return ($sum < 2 && $check == $sum) || ($sum >= 2 && $check + $sum == 11);
}
// Swift 3, based on @farzadshbfn work but modified a little
func isValidIranianNationalCode(input: String) -> Bool {
var digits = input.characters.flatMap { Int(String($0)) }
guard digits.count == 10 && digits.count == input.count else {
return false
}
let check = digits[9]
let sum = digits[0 ..< 9].enumerated().reduce(0) { $0 + $1.element * (10 - $1.offset) } % 11
return sum < 2 ? check == sum : check + sum == 11
}
// Kotlin, Android
fun isValidIranianNationalCode(input: String): Boolean {
if (!"^\\d{10}$".toRegex().matches(input))
return false
input.toCharArray().map(Character::getNumericValue).let {
val check = it[9]
val sum = (0..8).map { i -> it[i] * (10 - i) }.sum() % 11
return sum < 2 && check == sum || sum >= 2 && check + sum == 11
}
}
// Groovy, based on @mehrali work
boolean isValidIranianNationalCode(String input) {
if (!input?.matches('^\\d{10}$'))
return false
int check = input[9].toInteger()
int sum = (0..8).sum({ input[it].toInteger() * (10 - it) }) % 11
return ((sum < 2 && check == sum) || (sum >= 2 && check + sum == 11))
}
// Rust
fn is_valid_iranian_national_code(s: &str) -> bool {
let digits: Vec<u32> = s.chars()
.map(|x| x.to_digit(10))
.filter(|&x| x != None)
.map(|x| x.unwrap())
.collect();
if digits.len() != 10 { return false }
let check = digits[9];
let sum: u32 = (0..9).map(|x| digits[x] * (10 - x) as u32).sum();
let s = sum % 11;
(s < 2 && check == s) || (s >= 2 && check + s == 11)
}
// Haskell, contributed by @hzamani
import Data.Char
isValidNationalCode code =
length code == 10 && all isDigit code && if s < 2 then check == s else check + s == 11
where
digits = map digitToInt code
check = last digits
s = sum (map (\(d, i) -> d * (10 - i)) $ digits `zip` [0..8]) `mod` 11
// Erlang, contributed by @hzamani
is_valid_national_code(Code) ->
length(Code) == 10
andalso lists:all(fun(D) -> $0 =< D andalso D =< $9 end, Code)
andalso begin
ToDigit = fun(Char) -> Char - $0 end,
S = lists:sum(lists:map(fun({I, D}) -> D * (10 - I) end, lists:zip(lists:seq(0, 8), lists:droplast(lists:map(ToDigit, Code))))) rem 11,
Check = ToDigit(lists:last(Code)),
if
S < 2 -> Check == S;
true -> Check + S == 11
end
end.
// Elixir, contributed by @hzamani
fn input ->
if input =~ ~r/^\d{10}$/ do
[check | digits] =
input
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.reverse
s =
digits
|> Enum.with_index(2)
|> Enum.map(fn {digit, i} -> digit * i end)
|> Enum.sum
|> rem(11)
if s < 2 do check == s else check + s == 11 end
else
false
end
end
@amirkarimi

This comment has been minimized.

Copy link

amirkarimi commented Dec 25, 2014

Scala code doesn't work. """^\d{10}$""".r should become """^(\d{10})$""".r.

@ghasemy50

This comment has been minimized.

Copy link

ghasemy50 commented Mar 25, 2017

عالی دمت گرم واقعا زحمت کشیدی :-)

@Lithium-HD

This comment has been minimized.

Copy link

Lithium-HD commented Jun 7, 2017

for those who want to achieve this in Swift language for ios:

func isValidIranianNationalCode(testStr: String) -> Bool {
        let nRegEx = "^\\d{10}$"
        
        let nRegExTest = NSPredicate(format: "SELF MATCHES %@", nRegEx)
        if !nRegExTest.evaluate(with: testStr) {
            return false
        }
    
        
        let check = Int(testStr.substring(with: 9..<10))
   
        var sum = 0
        for i in stride(from: 0, to: 9, by: 1) {
            sum += Int(testStr[i])! * (10 - i);
        }
        sum %= 11;
        
        return (sum < 2 && check! == sum) || (sum >= 2 && check! + sum == 11);
    }

extension String {
    
    subscript (i: Int) -> Character {
        return self[index(startIndex, offsetBy: i)]
    }
    
    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }
    
    subscript (r: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound - r.lowerBound)
        return self[Range(start ..< end)]
    }
}
@qasimsina

This comment has been minimized.

Copy link

qasimsina commented Aug 2, 2017

@Lithium-HD
Your code doesn't work in Swift 3!

@hojatdelfan

This comment has been minimized.

Copy link

hojatdelfan commented Aug 15, 2017

this code is tested By swift 3.0 & 4.0

func isValidIranianNationalCode(testStr: String) -> Bool {
let nRegEx = "^\d{10}$"

    let nRegExTest = NSPredicate(format: "SELF MATCHES %@", nRegEx)
    if !nRegExTest.evaluate(with: testStr) {
        return false
    }
    
    
    let check = Int(testStr.substring(with: 9..<10))
    
    var sum = 0
    let arrayString = testStr.characters.map { String($0) }
    for i in stride(from: 0, to: 9, by: 1) {
        
        sum = sum + ( Int(arrayString[i])! * (10 - i) )
        
    }
    
    sum = sum % 11
    
    return (sum < 2 && check! == sum) || (sum >= 2 && check! + sum == 11)
}
@Elias-Heydarpour

This comment has been minimized.

Copy link

Elias-Heydarpour commented Nov 27, 2017

thanks,
very good!

@hajjijo

This comment has been minimized.

Copy link

hajjijo commented Feb 9, 2018

You are hero !!!

@alireza267

This comment has been minimized.

Copy link

alireza267 commented Feb 18, 2018

Excellent! thanks a lot.

@Mhs-220

This comment has been minimized.

Copy link

Mhs-220 commented Apr 10, 2018

Thank You! it's very helpful

@mm580486

This comment has been minimized.

Copy link

mm580486 commented Apr 12, 2018

Angular 2+

import { AbstractControl } from '@angular/forms';

export function ValidateNational(control: AbstractControl) {
 
  if (!/^\d{10}$/.test(control.value)){
    return false;
  }

  var check = parseInt(control.value[9]);
  var sum = 0;
  var i;
  for (i = 0; i < 9; ++i) {
      sum += parseInt(control.value[i]) * (10 - i);
  }
  sum %= 11;

  return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);

}


@AlirezaNoorali

This comment has been minimized.

Copy link

AlirezaNoorali commented Jul 2, 2018

How to validate iranian Melli Code (National Code or Code Melli) in android
بررسی صحت یا اعتبار سنجی کد ملی ایرانی در اندروید به زبان جاوا:

https://stackoverflow.com/a/44603571/6444297

@hamed2867

This comment has been minimized.

Copy link

hamed2867 commented Aug 7, 2018

سپاسگزار از زحمات شما، عالی بود

@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Oct 8, 2018

بعد از سال‌ها این اسکریپت دوباره به کارم آمد و نسخهٔ کاتلینش را اضافه کردم :)

@dehghani-mehdi

This comment has been minimized.

Copy link

dehghani-mehdi commented Oct 10, 2018

کد کامل نیست، مثلا 0000000000 رو صحیح تشخیص میده.

@hsharghi

This comment has been minimized.

Copy link

hsharghi commented Oct 22, 2018

Swift 4 version

    func isValidIranianNationalCode(input: String) -> Bool{
        let digits = input.map { Int(String($0)) }
        
        guard digits.count == 10 && digits.count == input.count else {
            return false
        }
        
        let check = digits[9]!
        let remainder = digits.prefix(upTo: 9).enumerated().reduce(0) { $0 + $1.element! * (10 - $1.offset) } % 11
        
        return remainder < 2 ? check == remainder : check + remainder == 11   
    }
@iMojtaba

This comment has been minimized.

Copy link

iMojtaba commented Oct 28, 2018

کد اصلاح شده برای ری اکت

export const checkNationalId = (input) => {
  if (
    !/^\d{10}$/.test(input)
    || input === '0000000000'
    || input === '1111111111'
    || input === '2222222222'
    || input === '3333333333'
    || input === '4444444444'
    || input === '5555555555'
    || input === '6666666666'
    || input === '7777777777'
    || input === '8888888888'
    || input === '9999999999'
  ) {
    return false;
  }

  const check = parseInt(input[9], 10);
  let sum = 0;
  let i;
  for (i = 0; i < 9; 1 + i) {
    sum += parseInt(input[i], 10) * (10 - i);
  }
  sum %= 11;

  return (sum < 2 && check === sum) || (sum >= 2 && check + sum === 11);
};

@sparse91

This comment has been minimized.

Copy link

sparse91 commented Dec 29, 2018

برای جاوا ۸ به نظر این جوری صحیح تره:

if (!value.matches("^\\d{10}$"))
    return false;

int check = Integer.parseInt(value.substring(9, 10));

int sum = IntStream.range(0, 9)
        .map(x ->
                Integer.parseInt(value.substring(x, x + 1)) * (10 - x))
        .sum() % 11;

return (sum < 2 && check == sum) || (sum >= 2 && check + sum == 11);
@mehrali

This comment has been minimized.

Copy link

mehrali commented Jan 21, 2019

Groovy version

boolean isValidIranianNationalCode(String input) {
    if (!input?.matches('^\\d{10}$'))
        return false
    int check = input[9].toInteger()
    int sum = (0..8).sum({ input[it].toInteger() * (10 - it) }) % 11
    return ((sum < 2 && check == sum) || (sum >= 2 && check + sum == 11))
}
@aghasoroush

This comment has been minimized.

Copy link

aghasoroush commented Feb 14, 2019

Thank you very much for your great effort man.
We also need to know whether digits are identical or not.
Here it is a custom validator for laravel which makes you able to validate incoming inputs with nationalId rule in your validation.
You should use this chunk of code in a registered ServiceProvider.

// https://gist.github.com/ebraminio/5292017#file-gistfile1-cs-L148  -> melli-card validators
// https://fa.wikipedia.org/wiki/%DA%A9%D8%A7%D8%B1%D8%AA_%D8%B4%D9%86%D8%A7%D8%B3%D8%A7%DB%8C%DB%8C_%D9%85%D9%84%DB%8C
Validator::extend('nationalId', function($attribute, $value, $parameters, $validator) {
    # check if input has 10 digits that all of them are not equal
    if (!preg_match("/^\d{10}$/", $value)) {
        return false;
    }

    // all digits are identical ex. 0000000000, 1111111111, ...
    if (count(array_unique(str_split($value))) == 1) {
        return false;
    }

    $check = (int) $value[9];
    $sum = array_sum(array_map(function ($x) use ($value) {
            return ((int) $value[$x]) * (10 - $x);
        }, range(0, 8))) % 11;

    return ($sum < 2 && $check == $sum) || ($sum >= 2 && $check + $sum == 11);
});
@gvmohzibat

This comment has been minimized.

Copy link

gvmohzibat commented Feb 20, 2019

In ES6, the fill method needs has 1-3 arguments. you need to change Array(9).fill() to Array(9).fill(undefined).
Or I prefer to use this code instead:

Array.from(new Array(9), (_, i) => +input[i] * (10 - i)).reduce((x, y) => x + y) % 11
@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Apr 4, 2019

@dehghani-mehdi @iMojtaba @aghasoroush توضیح بالای کد را یک بررسی مجدد کنید، ممنونم

@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Apr 4, 2019

@mehrali @sparse91 اعمال شد :)

@hzamani

This comment has been minimized.

Copy link

hzamani commented Jul 16, 2019

Haskell:

import Data.Char

isValidNationalCode code =
    length code == 10 && all isDigit code && if s < 2 then check == s else check + s == 11
    where
        digits = map digitToInt code
        check = last digits        
        s = sum (map (\(d, i) -> d * (10 - i)) $ digits `zip` [0..8]) `mod` 11
@hzamani

This comment has been minimized.

Copy link

hzamani commented Jul 16, 2019

Erlang:

is_valid_national_code(Code) ->
    length(Code) == 10
    andalso lists:all(fun(D) -> $0 =< D andalso D =< $9 end, Code)
    andalso begin
        ToDigit = fun(Char) -> Char - $0 end,
        S = lists:sum(lists:map(fun({I, D}) -> D * (10 - I) end, lists:zip(lists:seq(0, 8), lists:droplast(lists:map(ToDigit, Code))))) rem 11,
        Check = ToDigit(lists:last(Code)),
        if
            S < 2 -> Check == S;
            true  -> Check + S == 11
        end
    end.
@hzamani

This comment has been minimized.

Copy link

hzamani commented Jul 16, 2019

Elixir:

fn input ->
    if input =~ ~r/^\d{10}$/ do
        [check | digits] =
            input
            |> String.split("", trim: true)
            |> Enum.map(&String.to_integer/1)
            |> Enum.reverse
        s =
            digits
            |> Enum.with_index(2)
            |> Enum.map(fn {digit, i} -> digit * i end)
            |> Enum.sum
            |> rem(11)
         if s < 2 do check == s else check + s == 11 end
    else
        false
    end
end
@mahdigh99

This comment has been minimized.

Copy link

mahdigh99 commented Aug 5, 2019

ورژن جاوااسکریپت کار نمیکنه! هر چی میدی غلط تشخیص میده حتی ۱۱۱۱۱۱۱۱۱۱

@mahdigh99

This comment has been minimized.

Copy link

mahdigh99 commented Aug 5, 2019

بله هم کد ملی خودمو تست کردم هم ۱۰ تا ۱
علاوه بر پروژه توی کنسول لاگ فایرفاکس هم تست کردم نشد
Screen Shot 1398-05-14 at 18 48 05

@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Aug 5, 2019

لطفاً از نوع رشته ارسال کنید چون بعضی از شماره ملی‌ها دارای صفر در اول هستند و اعداد به نظر ورودی درستی نباشن برای همچین کاری، ممنون

@mahdigh99

This comment has been minimized.

Copy link

mahdigh99 commented Aug 5, 2019

ممنونم
توی کنسول حل شد اما توی پروژم به طرز عجیبی همچنان نمیشه
مشکل هم از همون تعداد اوله با اینکه دقیقا تعداد ارقامش ۱۰ تاست ولی بازم فالس میده

@mahdigh99

This comment has been minimized.

Copy link

mahdigh99 commented Aug 6, 2019

مشکلم حل شد
مشکل از اونجا بود که وقتی از
template engine
استفاده میکنی مرورگر بک اسلش ها رو اسکیپ میکنه
باید با همچین حالتی بنویسی تا اوکی بشه
/^\\d{10}$/

if (!/^\d{10}$/.test(input)) ===> if (!/^\\d{10}$/.test(input))

@riazi

This comment has been minimized.

Copy link

riazi commented Aug 17, 2019

کد اصلاح شده برای ری اکت

export const checkNationalId = (input) => {
  if (
    !/^\d{10}$/.test(input)
    || input === '0000000000'
    || input === '1111111111'
    || input === '2222222222'
    || input === '3333333333'
    || input === '4444444444'
    || input === '5555555555'
    || input === '6666666666'
    || input === '7777777777'
    || input === '8888888888'
    || input === '9999999999'
  ) {
    return false;
  }

  const check = parseInt(input[9], 10);
  let sum = 0;
  let i;
  for (i = 0; i < 9; 1 + i) {
    sum += parseInt(input[i], 10) * (10 - i);
  }
  sum %= 11;

  return (sum < 2 && check === sum) || (sum >= 2 && check + sum === 11);
};

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

@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Aug 17, 2019

این کد اصلی این صفحه نیست، شرط اعداد برابر نادرست است (و این بدترین شیوهٔ بررسی آن است، می‌توان آن را در همان عبارت باقاعدهٔ اصلی چا کرد) و در بالای صفحهٔ توضیح داده شده که چرا، اگر کاربرتان نمی‌خواهد اعداد واقعی دهد چه این شرط را بگذارید چه نه به شما اعداد واقعی نخواهد داد و آخر راهی برای دادن اعداد اشتباه پیدا خواهد کرد

@firouzyar

This comment has been minimized.

Copy link

firouzyar commented Oct 22, 2019

کد اصلاح شده برای ری اکت

export const checkNationalId = (input) => {
  if (
    !/^\d{10}$/.test(input)
    || input === '0000000000'
    || input === '1111111111'
    || input === '2222222222'
    || input === '3333333333'
    || input === '4444444444'
    || input === '5555555555'
    || input === '6666666666'
    || input === '7777777777'
    || input === '8888888888'
    || input === '9999999999'
  ) {
    return false;
  }

  const check = parseInt(input[9], 10);
  let sum = 0;
  let i;
  for (i = 0; i < 9; 1 + i) {
    sum += parseInt(input[i], 10) * (10 - i);
  }
  sum %= 11;

  return (sum < 2 && check === sum) || (sum >= 2 && check + sum === 11);
};

این کد مشکل داره وقتی شرط صحیح باشد مرورگر هنگ میکنه

@ebraminio

This comment has been minimized.

Copy link
Owner Author

ebraminio commented Oct 22, 2019

این کد پیشنهاد شده این صفحه نیست، لطفاً مطلب بالا صفحه و
http://www.fardanews.com/fa/news/127747
را بخوانید شاید نکته جالبی یافتید

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.