Skip to content

Instantly share code, notes, and snippets.

@ebraminio
Last active July 2, 2024 06:14
Show Gist options
  • Save ebraminio/5292017 to your computer and use it in GitHub Desktop.
Save ebraminio/5292017 to your computer and use it in GitHub Desktop.
Check Iranian National Code Validity - بررسی صحت کد ملی ایرانی - Clojure, C#, F#, Ruby, JavaScript, Dart, Python, Scala, Java 8, PHP, C, Go, Swift, Kotlin, Groovy, Rust, Haskell, Erlang, Elixir, PowerQuery M Language, VBA, R, Lua, Fortran, Pascal/Delphi, Excel, Stored Procedure / MySQL
// Check Iranian National Code Validity - Clojure, C#, F#, Ruby, JavaScript, Dart, Python, Scala, Java 8, PHP, C, Go, Swift, Kotlin, Groovy, Rust, Haskell, Erlang, Elixir, Power Query M Language, VBA, R, Lua, Fortran, Pascal/Delphi, Excel, Stored Procedure / MySQL
// بررسی صحت کد ملی ایران - کلوژر، سی‌شارپ، اف‌شارپ، روبی، جاوااسکریپت، دارت، پایتون، اسکالا، جاوا ۸، پی‌اچ‌پی، سی، گو، سوئیفت، کاتلین، گرووی، راست، هسکل، ارلنگ، الکسیر، پاورکوئری ام، وی‌بی ای، آر، لوآ، فرترن، پاسکال/دلفی، اکسل، مای‌اس‌کیوال
// در نسخه‌های قبل یکسان بودن اعداد نا معتبر تشخیص داده می‌شد ولی
// اعداد یکسان نامعتبر نیست https://web.archive.org/web/20170706081048/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)]
(if (< sum 2) (== check sum) (== (+ check sum) 11))
false))
// Ruby
def is_valid_iran_code(input)
return false if /^\d{10}$/ !~ input
check = Integer(input[9])
s = (0..8).sum {|x| Integer(input[x]) * (10 - x)} % 11
s < 2 ? check == s : 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 : check + sum == 11;
}
// F#
open System.Text.RegularExpressions
let isValidIranianNationalCode input =
if Regex.IsMatch(input, @"^\d{10}$") then
let check = Convert.ToInt32(input.Substring(9, 1))
let sum = (seq { 0 .. 8 }
|> Seq.map (fun x -> Convert.ToInt32(input.Substring(x, 1)) * (10 - x))
|> Seq.sum) % 11
if sum < 2 then check = sum else check + sum = 11
else
false
// JavaScript
function isValidIranianNationalCode(input) {
if (!/^\d{10}$/.test(input)) return false;
const check = +input[9];
const sum = input.split('').slice(0, 9).reduce((acc, x, i) => acc + +x * (10 - i), 0) % 11;
return sum < 2 ? check === sum : check + sum === 11;
}
// Dart
bool isValidIranianNationalCode(String input) {
if (!RegExp("^\\d{10}").hasMatch(input)) return false;
final check = int.parse(input[9]);
final sum = Iterable<int>.generate(9).map((x) => int.parse(input[x]) * (10 - x)).reduce((x, y) => x + y) % 11;
return sum < 2 ? check == sum : check + sum == 11;
}
// C
bool isValidIranianNationalCode(const char *input) {
for (unsigned i = 0; i < 10; ++i) if (input[i] < '0' || input[i] > '9') return false;
if (input[10]) return false;
unsigned check = input[9] - '0';
unsigned sum = 0;
for (unsigned i = 0; i < 9; ++i) sum += (int)(input[i] - '0') * (10 - i);
sum %= 11;
return sum < 2 ? check == sum : 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: str) -> bool:
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 check == s if s < 2 else 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
if (sum < 2) check == sum else 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 : check + sum == 11;
}
// PHP
function isValidIranianNationalCode(string $input): boolean {
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 : $check + $sum == 11;
}
// Swift, based on @farzadshbfn work but modified a little, tested with Swift 5.3.1
func isValidIranianNationalCode(input: String) -> Bool {
let digits = input.compactMap { 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
fun isValidIranianNationalCode(input: String): Boolean {
if (input.length != 10) return false
val digits = input.mapNotNull(Char::digitToIntOrNull).takeIf { it.size == 10 } ?: return false
val check = digits[9]
val sum = digits.slice(0..8).asSequence().mapIndexed { i, x -> x * (10 - i) }.sum() % 11
return if (sum < 2) check == sum else 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 : check + sum == 11
}
// Rust
fn is_valid_iranian_national_code(s: &str) -> bool {
let digits: Vec<u32> = s.chars().filter_map(|x| x.to_digit(10)).collect();
if s.len() != 10 || digits.len() != 10 {
return false;
}
let check = digits[9];
let sum = (0..9).map(|x| digits[x] * (10 - x) as u32).sum::<u32>() % 11;
if sum < 2 {
check == sum
} else {
check + sum == 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
// PowerQuery M Language, in a collaboration with Calak
(input as text) as logical =>
let
check = Number.From(Text.End(input, 1)),
s = Number.Mod(List.Sum(List.Transform({0..8}, each (10 - _) * Number.From(Text.At(input, _)))), 11)
in Text.Length(input) = 10 and
Text.Select(input, {"0".."9"}) = input and
(if s < 2 then check = s else check + s = 11)
// VBA, in a collaboration with Calak
Public Function IsValidIranianNationalCode(code As String) As Boolean
If Not code Like String(10, "#") Then Exit Function
Dim check As Byte, i As Byte, s As Integer
check = Mid(code, 10)
For i = 1 To 9
s = s + (11 - i) * Mid(code, i, 1)
Next i
s = s Mod 11
IsValidIranianNationalCode = IIf(s < 2, check = s, check + s = 11)
End Function
// R, by Calak
is_valid_iran_code <- function(input) {
if (!grepl('^[0-9]{10}$', input)) return (FALSE)
check <- as.integer(substr(input, 10, 10))
s <- t(10:2) %*% as.integer(unlist(strsplit(input, "")))[-10] %% 11
return (if (s < 2) check == s else check + s == 11)
}
// Lua
function is_valid_iranian_national_code(input)
if input:match(string.rep("%d", 10)) ~= input then return false end
local check = tonumber(input:sub(10, 10))
local sum = 0
for i = 1, 9 do
sum = sum + (11 - i) * tonumber(input:sub(index, index))
end
sum = sum % 11
return (sum < 2) and (check == sum) or (check + sum == 11)
end
// Fortran, by Calak
logical pure function is_valid_iranian_national_code(input)
character(10), intent(in) :: input; integer :: check, i, s
integer, parameter :: zero = ichar("0")
is_valid_iranian_national_code = .false.
if (verify(input, "0123456789") /= 0) return
check = ichar(input(10:)) - zero
s = mod(sum((/ ((11 - i) * (ichar(input(i:i)) - zero), i = 1, 9) /)), 11)
is_valid_iranian_national_code = merge(check == s, check + s == 11, s < 2)
end function is_valid_iranian_national_code
// Pascal/Delphi, by Calak
function isValidIranianNationalCode(input: string): boolean;
const s: integer = 0;
var check, i: byte;
begin
isValidIranianNationalCode := false;
if ord(input[0]) <> 10 then exit;
for i := 1 to 10 do if not (input[i] in ['0'..'9']) then exit;
val(input[10], check);
for i := 1 to 9 do inc(s, (11 - i) * (ord(input[i]) - ord('0')));
s := s mod 11;
isValidIranianNationalCode := ((s < 2) and (check = s) or (s >= 2) and (check + s = 11));
end;
// Excel 365, by Calak
= LAMBDA(input,
IF(
AND(LEN(input) = 10, ISNUMBER(--MID(input, SEQUENCE(10), 1))),
LET(
check, --RIGHT(input),
s, MOD(SUMPRODUCT(SEQUENCE(9, 1, 10, -1), --MID(input, SEQUENCE(9), 1)), 11),
IF(s < 2, check = s, check + s = 11)
)
)
)
// Stored Procedure, MySQL
DELIMITER $$
CREATE FUNCTION is_valid_iranian_national_code(input TEXT) RETURNS BOOLEAN DETERMINISTIC BEGIN
IF input NOT REGEXP '^[0-9]{10}$' THEN RETURN false; END IF;
SET @i = 1, @s = 0;
WHILE @i < 10 DO SET @s = @s + (11 - @i) * SUBSTR(input, @i, 1), @i = @i + 1; END WHILE;
SET @s = @s % 11, @check = +SUBSTR(input, -1);
RETURN IF(@s < 2, @check = @s, @check + @s = 11);
END $$
DELIMITER ;
@hassanKhademi
Copy link

سلام و ممنون
خدا خیرت بده

@ZargarAdel
Copy link

سلام و ممنون
لطفا به زبان SQL-Server هم کد را ترجمه کنید...
در پایگاه داده یک کوئری می خواهیم که کدهای ملی نامعتبر را فیلتر کند.

@ebraminio
Copy link
Author

ebraminio commented Nov 8, 2022

@ZargarAdel

به sql server دسترسی ندارم ولی برای mysql را قرار دادم، احتمالاً بتوانید آن را در sql server با کمی تغییر استفاده کنید 😊

@miladjalalli
Copy link

دمت گرم، عالی بود😊

@aghalati
Copy link

خیلی ممنون

دوستان من قصد استفاده از بخش php برای woocommerce را دارم، لطفا بفرمایید که کد زیر چه مشکلی دارد؟

`function isValidIranianNationalCode($input) {
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 : $check + $sum == 11;

}

add_filter( 'flexible_checkout_fields_custom_validation', 'wpdesk_fcf_custom_validation_CodeMelli' );
/**

  • Add custom URL validation

*/
function wpdesk_fcf_custom_validation_CodeMelli( $custom_validation ) {
$custom_validation['_billing_code_melli'] = array(
'label' => 'Code Melli',
'callback' => 'isValidIranianNationalCode'
);

return $custom_validation;

}

`

@ebraminio
Copy link
Author

ebraminio commented Dec 17, 2023

سلام @mbgame اعداد تکراری نامعتبر نیست https://web.archive.org/web/20170706081048/http://www.fardanews.com/fa/news/127747/رندترین-شماره-ملی-بلای-جان-صاحبش-شد قبلاً همین regular expression را داشتیم که حذف کردم و بالای این صفحه هم این موضوع رو نوشته‌ام، اگر کاربر قصد دور زدن ورود عدد را داشته باشد به هر حال راهی برای دور زدن آن پیدا می‌کند و راه‌حل، اضافه کردن قانونی ناموجود نیست

@reza-sdo
Copy link

thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment