Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Regex Split Credit Card Numbers

I have a credit card number that will contain up to 16 digits and I am trying to split it apart: Ex. (1234567891234567) to: (1234 5678 9123 4567).

I'm still a pretty big RegExp newb, but I have ^(\d{4})(\d{4})?(\d{4})?(\d{4})?

The regex will match when there is exactly 4 numbers for at least 2 groups (1234 5678) but will fail on (1234 56)

If I add {2,4} I get things like (1234 56 78) which I don't want.

Any help is greatly appreciated

UPDATE 1: The goal is to have the credit card number split apart as the user is typing it: So 123456 would automatically become: 1234 56, etc. etc.

UPDATE 2: The easiest way to explain what I am trying to do is here: https://stripe.com/docs/tutorials/checkout and click on Pay with Card, then type in the "credit card" field, you will see the numbers shift as you are typing.

like image 437
Corey Avatar asked Aug 03 '14 04:08

Corey


3 Answers

I was going to just delete this since my answer isn't exactly what I was looking for in this question, but I can't delete it so:

I was able to create the desired functionality through the following function(s):

(Here is a Working Example: http://jsfiddle.net/7vH6T/ )

    var creditcards = { 
        list:[
            {
                brand:          'American Express',
                image:          '/images/creditcards/american-express.png',
                verification:   '^3[47][0-9]',
                separation:     '^([0-9]{4})([0-9]{6})?(?:([0-9]{6})([0-9]{5}))?$',
                hidden:         '**** ****** *[0-9][0-9][0-9][0-9]',
                accepted:       true,
                length:         15
            },
            {
                brand:          'MasterCard',
                image:          '/images/creditcards/mastercard.png',
                verification:   '^5[1-5][0-9]',
                separation:     '^([0-9]{4})([0-9]{4})?([0-9]{4})?([0-9]{4})?$',
                hidden:         '**** **** **** [0-9][0-9][0-9][0-9]',
                accepted:       true,
                length:         16
            },
            {
                brand:          'Visa',
                image:          '/images/creditcards/visa.png',
                verification:   '^4[0-9]',
                separation:     '^([0-9]{4})([0-9]{4})?([0-9]{4})?([0-9]{4})?$',
                hidden:         '**** **** **** [0-9][0-9][0-9][0-9]',
                accepted:       true,
                length:         16
            },
            {
                brand:          'Discover',
                image:          '/images/creditcards/discover.png',
                verification:   '^6(?:011|5[0-9]{2})[0-9]',
                separation:     '^([0-9]{4})([0-9]{4})?([0-9]{4})?([0-9]{4})?$',
                hidden:         '**** **** **** [0-9][0-9][0-9][0-9]',
                accepted:       false,
                length:         16
            },
            {
                brand:          'Diners Club',
                image:          '/images/creditcards/diners-club-international.png',
                verification:   '^3(?:0[0-5]|[68][0-9])[0-9]',
                separation:     '^([0-9]{4})([0-9]{4})?([0-9]{4})?(?:([0-9]{4})([0-9]{4})([0-9]{2}))?$',
                hidden:         '**** **** **[0-9][0-9] [0-9][0-9]',
                accepted:       false,
                length:         14
            },
            {
                brand:          'JCB',
                image:          '/images/creditcards/jcb.png',
                verification:   '^(?:2131|1800|35[0-9]{3})[0-9]',
                separation:     '^([0-9]{4})([0-9]{4})?([0-9]{4})?([0-9]{4})?$',
                hidden:         '**** **** **** [0-9][0-9][0-9][0-9]',
                accepted:       false,
                length:         16
            }
        ], 
        active:null 
    };


  //On Keydown
  $('input[name="creditcard"]').keydown(function(e){


    //Preset Data
    var card = $(this).val().replace(/[^0-9]/g,''),
        trim = $.trim( $(this).val().slice(0,-1) );


    //Find the Credit Card
    for( var i=0; i<creditcards.list.length; i++ ){

      //Check the Type
      if(card.match( new RegExp(creditcards.list[i].verification) )){

        //Set the Active Card
        creditcards.active = i;


        //Add Credit Card Icon
        if( $(this).next('img').length == 0 ){

          //Remove any possible Error
          $(this).next('small').remove();

          //Add the Image
          $(this).after('<img src="'+creditcards.list[i].image+'" alt="'+creditcards.list[i].brand+'" style="height:20px; position:relative; top:5px;" />');

        }


        //If the Credit Card is NOT accepted, Show the Error
        if( !creditcards.list[i].accepted && $(this).nextAll('small').length == 0 ){

          //Show Error
          $(this).next('img').after('<small style="margin-left:5px; color:#F00;">'+'Creditcard Not Accepted'+'</small>');

        }

        //End the Loop
        break;

      }

    }



    //Show Invalid Card
    if( creditcards.active == null && card.length > 4 && $(this).nextAll('small').length == 0 ){

      //Show Error
      $(this).after('<small style="margin-left:5px; color:#F00;">'+'Invalid Credit Card'+'</small>');

    }



    //Preset they Key
    key = creditcards.active !== null? creditcards.active : 1 ;


    //If the Last Character is a String, Remove it
    if( e.keyCode == 8 && trim != $(this).val().slice(0,-1) ){

      //Set the New Value
      $(this).val( trim );

      //Stop from Completing
      e.preventDefault();

      //Return
      return;

    }


    //Limit the Length of the Card, Allow Keys
    if( card.length >= creditcards.list[ key ].length && $.inArray(e.keyCode, [37, 38, 39, 40, 46, 8, 9, 27, 13, 110, 190]) === -1 && !e.metaKey && !e.ctrlKey ){
      e.preventDefault();
      return;
    }

    //Add a Space if the Regex Passes
    if( new RegExp(creditcards.list[ key ].separation).exec( card ) && e.keyCode >= 48 && e.keyCode <= 57 ){
      $(this).val( $(this).val() + ' ' );
    }

    //Return
    return;

  });



























  //On Key up Ensure Card is Validated
  $('input[name="creditcard"]').keyup(function(e){

    //Get the Card
    var card = $(this).val().replace(/[^0-9]/,'');

    //Check if the Card is Active
    if( creditcards.active !== null && !card.match( new RegExp(creditcards.list[ creditcards.active ].verification) ) ){

        //Remove any Existing Error
        $(this).nextAll('small').remove();

        //If Not, Remove the Icon
        $(this).next('img').remove();

        //Set Active to NULL
        creditcards.active = null;

    }else
    if( card.length < 4 ){

      //Remove Invalid Card Error
      $(this).next('small').remove();

    }

  });


































  $('input[name="creditcard"]').on('paste',function(e){

    //Save the Element
    var el    = this;

    //Set Timeout to Run Function
    setTimeout(function(){

      //Save the Card
      var card = $(el).val().replace(/[^0-9]/g,'');

      //Remove all but numbers
      $(el).val( card );

      //Prepare the Keydown Event
      var e = jQuery.Event('keydown',{
        which:    37,
        keyCode:  37
      });


      //Trigger Keydown
      $(el).trigger(e).promise().done(function(e){


        //Preset they Key
        key = creditcards.active !== null? creditcards.active : 1 ;

        //Force the Card Length
        card.substr( 0 , creditcards.list[ key ].length );

        //Separate the Card
        var separation  = new RegExp(creditcards.list[ key ].separation).exec( card ),
            storage     = '';

        //Find the Closest Separation Point
        while( !separation && card.length > 1 ){
          storage     = card.charAt( card.length - 1 );
          card        = card.slice(0,-1);
          separation  = new RegExp(creditcards.list[ key ].separation).exec( card );
        }

        //If there was a Separation
        if( separation ){

          //A Holder for all of the Separation that is defined
          var separated = [];

          //Remove all Undefined Separation Fields
          for( var i=0; i<separation.length; i++){
            if( typeof separation[i] != 'undefined' ) separated.push( separation[i] );
          }

          //Build the String
          var string = separated.slice(1).join(' ') + (storage!=''? ' '+storage : '' )

          //Add the Separated Value
          $(el).val( string )

        }        

      //End $(el).trigger(e).promise().dome(function(e){
      });

    //End setTimeout(function(){
    },0);

  //End $(input[name="creditcard"]
  });
like image 169
Corey Avatar answered Oct 08 '22 23:10

Corey


Simply replace every four digits in the original string with the same digits followed by a space, like this

console.log("123456789101112".replace(/(\d{4}(?!\s))/g, "$1 "));
like image 31
thefourtheye Avatar answered Oct 09 '22 00:10

thefourtheye


I think there are many developers who implement credit card transaction with Stripe. Here is the example. Also, the accepted answer is too complicated and other ones won't work for "American Express".

let cardNumber;
let brand = Stripe.card.cardType(value)
if (brand === "American Express") {
  let tempVal = value.replace(/\s/g, '');
  cardNumber = (tempVal.slice(0,4).replace(/(.{4})/g, '$1 ') + 
    tempVal.slice(4,10).replace(/(.{6})/g, '$1 ') +
    tempVal.slice(10,15)).trim();
} else {
  cardNumber = value.replace(/\s/g, '').replace(/(.{4})/g, '$1 ').trim();
}
return cardNumber

I use helper function of stripe.js only for detecting the brand. So, you can use the rest even you are not using Stripe.

like image 29
Atsuhiro Teshima Avatar answered Oct 09 '22 00:10

Atsuhiro Teshima