Add delimiter to string at irregular lengths - Javascript

Viewed 64

I'm looking at auto populating hyphen's are irregular lengths for an HTML input field.

After the 2nd digit/character
After the 6th digit/character
After the 13th digit/character
12-3456-7891234-00000

I've come up with the below code which works fine at adding the hyphen's. Using backspace however is destroying the logic. Is there anyway I can achieve this using regex perhaps where it considers the entire string to process the split ?

var newFoo = '';
$('.nzPhoneNumber').on('change keydown paste input', function(){
  var foo = $(this).val();
  if (foo.length === 2) {
    newFoo = foo.concat('-')
    $(this).val(newFoo);
  } else if (foo.length === 7) {
    newFoo = newFoo + foo.substring(3,7) + '-'
    $(this).val(newFoo);
  } else if (foo.length === 15) {
    newFoo = newFoo + foo.substring(8,15) + '-'
    $(this).val(newFoo);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="nzPhoneNumber" />

Repl Link

2 Answers

You can use a pattern that will match consecutive optional patterns and replace with a custom logic.

Here is the code:

const re  = /^(\d{2})(?:(\d{1,4})(?:(\d{1,7})(\d*))?)?$/;

$('.nzPhoneNumber').on('change keydown paste input', function(){
  var foo = $(this).val();
  $(this).val(foo.replace(/\D/g,'').replace(re, (_,a,b,c,d) =>  
   a + 
    ( b ? `-${b}` : "") + 
     ( c ? `-${c}` : "") + 
      ( d ? `-${d}` : "") ));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="nzPhoneNumber" />

Details:

  • .replace(/\D/g,'') - the first action is to remove all non-digit chars from the input string
  • .replace(re, (_,a,b,c,d) => - now replace with the custom regex, once the match is found, assign Group 1 to a, Group 2 to b, Group 3 to c and Group 4 to d
  • a + ( b ? `-${b}` : "") + ( c ? `-${c}` : "") + ( d ? `-${d}` : "") ) - this is the dynamically built replacement string: first, a is used at the start (as it always matches), then - + Group 2 value are added if Group 2 matched at all, otherwise an empty string is appended to a, next, - + Group 3 value are added if Group 3 matched (else an empty string is appended) and the same thing happens next with Group 4 (d).

The /^(\d{2})(?:(\d{1,4})(?:(\d{1,7})(\d*))?)?$/ pattern matches:

  • ^ - start of a string
  • (\d{2}) - Capturing group 1: two digits
  • (?:(\d{1,4})(?:(\d{1,7})(\d*))?)? - an optional sequnce of (note each subsequent pattern can only match if the preceding one matches):
    • (\d{1,4}) - Group 2: one to four digits
    • (?:(\d{1,7})(\d*))?)? - an optional sequnce of
      • (\d{1,7}) - Group 3: one to seven digits
      • (\d*) - zero to five digits
  • $ - end of string.

See the regex demo.

NOTE: If the last number cannot have more than five digits, use (?:(\d{1,5})\d*)? instead of last (\d*): /^(\d{2})(?:(\d{1,4})(?:(\d{1,7})(?:(\d{1,5})\d*)?)?)?$/.

Generally creating input format has problem in backspace and selecting string length. You should exclude backspace key in events or add one number to target length of string (It is because prevent to create problem when delete of string by backspace).

Anyway i selected second case. So i added one to your target length. Also used array, loop and regex to simplify the code.

$('.nzPhoneNumber').on('change keydown paste input', function(e){
  var foo = $(this).val();
  [3, 8, 16].forEach((item) => {
    if (foo.length == item)
      $(this).val(foo.replace(/(\d)(?=\d$)/, "$1-"));
  })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="nzPhoneNumber" />

Related