Created
March 7, 2019 02:05
-
-
Save averykhoo/d373123209591f98def15c8be8de315d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://en.wikipedia.org/wiki/National_Registration_Identity_Card | |
# http://www.ngiam.net/NRIC/ | |
# http://www.ngiam.net/NRIC/NRIC_numbers.pdf | |
import random | |
weights = [2, 7, 6, 5, 4, 3, 2] | |
local_alphas = 'JZIHGFEDCBA' | |
foreign_alphas = 'XWUTRQPNMLK' | |
alt_weights = [9, 4, 5, 6, 7, 8, 9] | |
alt_local_alphas = 'JABCDEFGHIZ' | |
def checksum_alpha(digits, init_alpha='S'): | |
# sanity check | |
assert len(digits) == 7 | |
# dot product | |
checksum = sum(weight * int(digit) for weight, digit in zip(weights, digits)) | |
# offset based on initial letter | |
if init_alpha.lower() in 'sf': | |
checksum += 0 | |
elif init_alpha.lower() in 'tg': | |
checksum += 4 | |
else: | |
pass | |
# return from appropriate alphabet | |
if init_alpha.lower() in 'st': | |
return local_alphas[checksum % 11] | |
elif init_alpha.lower() in 'fg': | |
return foreign_alphas[checksum % 11] | |
else: | |
return None | |
def validate(ic): | |
# cleanup | |
ic = ic.strip() | |
# catch malformed input | |
try: | |
return ic[8] == checksum_alpha(ic[1:8], ic[0]) | |
except: | |
return None | |
def generate(year=None, local=None): | |
# randomize unknown year | |
if year is None: | |
year = random.choice(range(1901, 2020)) | |
else: | |
assert 1799 < year < 2100 | |
# randomize unknown local/foreign | |
if local is None: | |
local = bool(random.getrandbits(1)) | |
# first two digits | |
if local: | |
if year > 1967: | |
digits = str(year)[-2:] | |
else: | |
# in reality there's probably some distribution over the other digits too | |
digits = random.choice('01') + str(random.randint(0, 9)) | |
else: | |
# much is unknown about fins, this seems incorrect | |
if year > 2008: | |
digits = random.choice('45678901') + str(random.randint(0, 9)) | |
else: | |
digits = random.choice('23') + str(random.randint(0, 9)) | |
# now append more digits | |
digits += str(random.randint(0, 99999)).rjust(5, '0') | |
# find first alphabet | |
init_alpha = '------------------sst' if local else '------------------ffg' | |
init_alpha = init_alpha[year // 100] | |
# last alphabet and capitalize | |
final_alpha = checksum_alpha(digits, init_alpha) | |
out = init_alpha + str(digits) + final_alpha | |
return out.upper() | |
if __name__ == '__main__': | |
print validate('S0000001I') # Yusof bin Ishak | |
print validate('S0000002G') # Lee Kuan Yew | |
print validate('S0000003E') # Kwa Geok Choo | |
print checksum_alpha('9876543', init_alpha='S') | |
print checksum_alpha('3456789', init_alpha='G') | |
print generate(2019, True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment