1

I'm not receiving the correct output from the credit card detection jQuery I've put together. The keyup event calls a function, creditCardTypeFromNumber(num), and the credit card type is supposed to be detected. Unfortunately, the only thing that is returned is 'UNKNOWN' no matter what value is typed in. I've used 6011 (discover), 5155 (MasterCard), and 4147 (Visa), none of which works.

I used the RegEx of each Credit Card type from the post here:

How do you detect Credit card type based on number?

And I put these two functions together based on what was done here:

Jquery find credit card type

I've put together a JSFiddle to show it not working. If someone could help me, I'd really appreciate it. Thanks

http://jsfiddle.net/nx6bbjzx/

creditCardTypeAction();

/**
  * Detect Credit Card Type Function
  */
function creditCardTypeAction(){
    $('.creditcardnumber').on('keyup', function(){
        if($(this).val().length >= 4){
            cardType = creditCardTypeFromNumber($(this).val());
        }
    });
}

function creditCardTypeFromNumber(num) {

    // first, sanitize the number by removing all non-digit characters.
    num = num.replace(/[^\d]/g,'');

    // MasterCard
    if (num.match(/^5[1-5][0-9]{5,}$/)) {
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.mastercard').addClass('active');

        alert('MasterCard');
        return 'MasterCard';

    // Visa
    } else if ( num.match(/^4[0-9]{6,}$/) ) {
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.visa').addClass('active');

        alert('Visa');
        return 'Visa';

    /* AMEX */
    } else if (num.match(/^3[47][0-9]{5,}$/)) {
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.amex').addClass('active');

        alert('AMEX');
        return 'AMEX';

    // Discover
    } else if (num.match(/^6(?:011|5[0-9]{2})[0-9]{3,}$/)) {
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.discover').addClass('active');

        alert('Discover');
        return 'Discover';

    // Diners Club
    } else if (num.match(/^3(?:0[0-5]|[68][0-9])[0-9]{4,}$/)){
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.diners').addClass('active');

        alert('Diners Club');
        return 'Diners Club';

    // JCB
    } else if (num.match(/^(?:2131|1800|35[0-9]{3})[0-9]{3,}$/)){
        $('.cardsacceptedicon').removeClass('active');
        $('.cardsacceptedicon.jcb').addClass('active');

        alert('JCB');
        return 'JCB';
    }

    alert('UNKNOWN');
    return 'UNKNOWN';
}
Community
  • 1
  • 1
Pegues
  • 1,693
  • 2
  • 21
  • 38
  • 1
    The JSFiddle appears to find the correct card type. What's not working? – bozdoz May 02 '15 at 23:23
  • I get UNKNOWN returned every time no matter what 4 digits I enter. I've entered the above example numbers in the jsfiddle, and every time it returns UNKNOWN to me. – Pegues May 02 '15 at 23:26
  • @ScriptsConnect How many characters provided to `input` returning "UNKNOWN" ? "4147" appear to require seven characters `num.match(/^4[0-9]{6,}$/)` to return match ? – guest271314 May 02 '15 at 23:36
  • Thanks @guest271314, that seems to be the problem. The only test I did was switched from 4 (which I have in the JSFiddle) to 6, and it was still not working for me. I just switched it to 7 and everything seems to work now. – Pegues May 02 '15 at 23:40
  • @bozdoz, I now see what you mean by saying that it finds the correct card type. I was never typing more than 4 (and 6 when I changed the length) and I was not finding the correct card type. – Pegues May 02 '15 at 23:43

3 Answers3

4

It's working correctly as far as I can tell.

The problem is that you're only entering 4 digits, which isn't enough to identify the cards - the patterns that those regular expressions look for aren't that simple.

Try entering 6011000 for example and you'll see it identified as "Discover".

Also your code could be more concise / maintainable :

    function creditCardTypeFromNumber( num ) {
    // Sanitise number
    num = num.replace(/[^\d]/g,'');

    var regexps = {
        'mastercard' : /^5[1-5][0-9]{5,}$/,
        'visa' : /^4[0-9]{6,}$/,
        'amex' : /^3[47][0-9]{5,}$/,
        'discover' : /^6(?:011|5[0-9]{2})[0-9]{3,}$/,
        'diners' : /^3(?:0[0-5]|[68][0-9])[0-9]{4,}$/,
        'jcb' : /^(?:2131|1800|35[0-9]{3})[0-9]{3,}$/,
        'unknown' : /.*/,
    };

    for( var card in regexps ) {
        if ( num.match( regexps[ card ] ) ) {
            console.log( card );
            $( '.cardsacceptedicon' ).removeClass( 'active' );
            $( '.cardsacceptedicon.' + card ).removeClass( 'active' );
            $( 'div.ccvalue' ).html( card );
            return card;
        }
    }
}

This way you can add new cards just by pasting in the new regular expression above 'unknown' :)

sqrbrkt
  • 131
  • 6
  • You're absolutely right. With the post from guest271314, he pointed out that for 4147 it required 7 characters. My knowledge is limited with RegEx, and any time I need an expression I just copy and paste it. I just changed it to 7 characters, and it works for all of them. Do you suggest I change the required min input to 7 or more? – Pegues May 02 '15 at 23:42
  • You could but it doesn't really make a difference since shorter inputs won't pass any of the regular expression tests. – sqrbrkt May 02 '15 at 23:44
  • Updated my answer above with a suggested code rewrite... just for fun really but also to get you thinking :) – sqrbrkt May 03 '15 at 00:02
  • Thank you very much sqrbrkt. That is great! And what you provided me will help me better use regex in my work in the future! – Pegues May 03 '15 at 00:17
1

I'm not convinced your regexs are correct for the way you are using them? Try them out at https://regex101.com/.

The route cause seems to be the the qualifiers e.g. [0-9]{5,} for master card is expecting between 5 and an unlimited number of digits, which won't match what you are entering. I would suggest the master card regex might need to be more like ^5[1-5][0-9]{2}.

saml
  • 794
  • 1
  • 9
  • 20
  • the RegEx I'm using for each card type is from here: http://stackoverflow.com/questions/72768/how-do-you-detect-credit-card-type-based-on-number?lq=1 Are these values not as good, and there are other more preferred RegEx values for credit card type? – Pegues May 02 '15 at 23:51
  • That post is very useful indeed, but it looks like there they are waiting for the entire card number to be entered (or at least more of it) before validating. Do you have to write this yourself? Since this isn't unique functionality, why reinvent the wheel... http://jquerycreditcardvalidator.com/ – saml May 02 '15 at 23:55
  • I just wanted simple functionality so I could highlight the correct card by adding the class 'active' to the card icon. I do agree with not reinventing the wheel, but mostly if pertaining to something I already know. I don't know RegEx, and I need to practice it in order to understand it better. I will take a look at the link you provided. It looks very interesting. Thanks Sam! – Pegues May 03 '15 at 00:00
  • If you're aiming for simple - carry on with your regex's but they do need some editing! – saml May 03 '15 at 00:38
1

The type of credit or debit card is find out based on number. For this we need send all entered numbers to below function.

getCardType(number) {
  let cards = {
    VISA: /^4[0-9]{12}(?:[0-9]{3})?$/,
    MASTER: /^5[1-5][0-9]{14}$/,
    AEXPRESS: /^3[47][0-9]{13}$/,
    DINERS: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
    DISCOVERS: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
    JCB: /^(?:2131|1800|35\d{3})\d{11}$/,
    BCGLOBAL: /^(6541|6556)[0-9]{12}$/,
    INSTAPAYMENT: /^63[7-9][0-9]{13}$/,
    CARTEBLANCHE: /^389[0-9]{11}$/,
    KOREANLOCAL: /^9[0-9]{15}$/,
    LASER: /^(6304|6706|6709|6771)[0-9]{12,15}$/,
    MAESTRO: /^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$/,
    SOLO: /^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$/,
    SWITCH: /^(4903|4905|4911|4936|6333|6759)[0-9]{12}|(4903|4905|4911|4936|6333|6759)[0-9]{14}|(4903|4905|4911|4936|6333|6759)[0-9]{15}|564182[0-9]{10}|564182[0-9]{12}|564182[0-9]{13}|633110[0-9]{10}|633110[0-9]{12}|633110[0-9]{13}$/,
    UNIONPAY: /^(62[0-9]{14,17})$/,
    VISAMASTER: /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$/
  };

  for (var card in cards) {
    if (cards[card].test(number)) {
      return card;
    } else {
      return 'INVALID'
    }
  }
}

This function will return the type of card. Try it. Enjoy!

David Buck
  • 3,752
  • 35
  • 31
  • 35