Skip to content

Instantly share code, notes, and snippets.

@DiegoSalazar
Last active February 12, 2024 05:09
Star You must be signed in to star a gist
Save DiegoSalazar/4075533 to your computer and use it in GitHub Desktop.
Luhn algorithm in Javascript. Check valid credit card numbers
// Takes a credit card string value and returns true on valid number
function valid_credit_card(value) {
// Accept only digits, dashes or spaces
if (/[^0-9-\s]+/.test(value)) return false;
// The Luhn Algorithm. It's so pretty.
let nCheck = 0, bEven = false;
value = value.replace(/\D/g, "");
for (var n = value.length - 1; n >= 0; n--) {
var cDigit = value.charAt(n),
nDigit = parseInt(cDigit, 10);
if (bEven && (nDigit *= 2) > 9) nDigit -= 9;
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) == 0;
}
@Brilliand
Copy link

@Maxhodges - To generate a check digit, set bEven to true initially, and return (1000 - nCheck) % 10.

@MohamedAlaa
Copy link

Execution time is very high: 35128.324ms

I've tried another Algorithm and it reported 0.059ms https://gist.github.com/ShirtlessKirk/2134376

@manishatGit
Copy link

Quite helpful !!

@javierverb
Copy link

Thanks!!! great work! 😄

@kendepelchin
Copy link

Great!

@mscheffer
Copy link

@mohamed execution time can't be 35 seconds !!

@chetankmayank
Copy link

hi..can i get the code for aadhar card number validation using javascript and c#

@tkMageztik
Copy link

awesome, thank you so much.

@fullstacked
Copy link

This is not working with Amex cards. Can anyone pls guide me. Thanks.

@volkerbohn
Copy link

Nice work! Thanks!

@anderconal
Copy link

Awesome work, thanks!

@ayushya
Copy link

ayushya commented Apr 20, 2017

Code Works great.

Although nDigit variable declared on Line 7 is not being used[ and can be removed ] since its been redeclared inside the for loop.

Correct me if wrong @DiegoSalazar

Copy link

ghost commented May 26, 2017

I noticed one a little mistake in the end of the script;
If you type '0' or '00' or '0000000000' you will get true

My resolve to line 22:
return (nCheck !== 0) && (nCheck % 10) == 0

What do you think ?

@maxkremer
Copy link

ndigit is defined twice. jshint complains . line 12

@Natanagar
Copy link

Nice work, thank you!

@dwhyte4
Copy link

dwhyte4 commented Mar 3, 2018

can you explain why use the operators in nDigit -= 9; and bEven = !bEven;

@MacroMan
Copy link

@dwhyte4
bEven = !bEven is a reversal, so bEven switches between true and false on each iteration of the loop, because each even digit is doubled as per the ISO/IEC 7812 spec.
nDigit -= 9; is to bring the number back between 1 and 9 if it's a double digit number (as per the ISO/IEC 7812 spec). This is the same effect as adding the 2 digits of the number together, which is what the spec says.

See https://en.wikipedia.org/wiki/Luhn_algorithm#Description for more info.

@craxidile
Copy link

Good job!

@nic0latesla
Copy link

Thanks bro

@web-apply
Copy link

web-apply commented Oct 21, 2018

i used to this algorithm in php master card generator script on Credit Card Generator with money and Free Credit Card Generator App. The rightmost digit is the Check digit value. We multiply the 1., 3., 5… .. values by 2, starting from the check digit value. (2nd, 4th, 6th… values remain the same.)
If the sum of the values is greater than 9, we add their numbers and find the sum of the numbers.
All the figures finally obtained are added up.
The sum of the numbers is multiplied by 9.
The last digit of the obtained number is the check digit value.

@weider86-zz
Copy link

Thank you! It works nice!

I only added a validation to empty string (""), because it was returning true. Thank you a lot!

@pranith-bm-ai
Copy link

I tried this out, but I realised I was looking rather naively at my problem. This works great at evaluating the complete card number.

I wanted to evaluate the card number while it is being typed, but I found there are challenges in determining the length of card number (can range from 13 to 19 digits) preemptively.

@DiegoSalazar
Copy link
Author

@pranith-bm-ai You can deduce from the first few numbers what kind of credit card it is and then you'll know what its length is supposed to be, see: https://www.freeformatter.com/credit-card-number-generator-validator.html#cardFormats

@altsanti
Copy link

I would add the line "if (!value) return false;" on top, to also take care of the situation of an empty input (or input with spaces).

@emandeguzman
Copy link

emandeguzman commented Apr 23, 2020

I tested against https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm

76009244561 did not return true

But I'm not sure if this number is really valid. all luhn verification code seem to fail when I use this number.

@JonHualde
Copy link

Working well, thank you very much Diego!

@sureshshivale
Copy link

sureshshivale commented Jul 17, 2020

Thank you! Nice work !
I'm Getting false result for Dankort (PBS) | 76009244561

Can someone answer for me on this ?

@mariacosta07911
Copy link

Thanks! Great Job!
I used this Credit Card Generator and it's showing almost accurate result.
they maintained maximum bank's bin code database. you must have to visit this site.

@finch0921
Copy link

Hi buddy,
I pull your code in my local repository, I found issues with your code It validate all types of Credit cards (like Amex, Visa, Diners Club) most of the card number are found invalid.

After that I use credit card validator on CardGenerators.com that gives me perfect result. It also validate 15, 16 and 19 digit credit cards.

@Tofandel
Copy link

Tofandel commented Sep 17, 2021

The code can be rewritten as:

function valid_credit_card(value) {
  // Accept only digits, dashes or spaces
	if (/[^0-9-\s]+/.test(value)) return false;

	// The Luhn Algorithm. It's so pretty.
	let nCheck = 0;
	value = value.replace(/\D/g, "");

	for (let n = 0; n < value.length; n++) {
		let nDigit = parseInt(value[n], 10);

		if (!((n + value.length) % 2) && (nDigit *= 2) > 9) nDigit -= 9;

		nCheck += nDigit;
	}

	return (nCheck % 10) === 0;
}

Or even cleaner

export const luhn = (value) => {
    let nCheck = 0;
    if (value && /[0-9-\s]+/.test(value)) {
        value = value.replace(/\D/g, '');

        value.split('').forEach((v, n) => {
            let nDigit = parseInt(v, 10);

            if (!((value.length + n) % 2) && (nDigit *= 2) > 9) {
                nDigit -= 9;
            }

            nCheck += nDigit;
        });
    }

    return (nCheck % 10) === 0;
};

@asfo
Copy link

asfo commented Feb 24, 2023

A shitty one-liner:

const luhn = numbers => numbers.split('').map((value, index) => index % 2 === 0 ? Number(value) * 2 <= 9 ? Number(value) * 2 : Number(Number(`${Number(value) * 2}`.split('')[0]) + Number(`${Number(value) * 2}`.split('')[1])) : Number(value)).reduce((a, b) => a + b).toString().split('')[1] === '0';

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