4

This Perl script is what I want to implement in JavaScript (source):

s/([0-9]+)/sprintf('%04d',$1)/ge;

Obviously sprintf is not available in JavaScript, but I know you can build a function that work directly on the number of concern, however in my case I have a long string containing possibly multiple numbers to convert string such as this: abc8 23 123 into this: abc000008 000023 000123 (using 6 digits as an example).

So it's either some clever regex that I don't get, or somehow find some way to split the long string into an array of distinct string and numbers and only act on the number one by one.

I really want to avoid the latter approach because 1) Speed is an issue in this case, and 2) The regex involved in splitting strings at the right place seems harder than adding leading zeros at this point.

In the end, is there any other way to go about it with JavaScript's regex?

Community
  • 1
  • 1
Shaw
  • 151
  • 1
  • 8

4 Answers4

7

You can use a regular expression to find the numbers, and replace them with a value from a function:

s = s.replace(/\d+/g, function(m){
  return "00000".substr(m.length - 1) + m;
});

Demo: http://jsfiddle.net/Guffa/sEUHY/

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Short and sweet! Btw. any reason for the `m.length - 1` instead of just `m.length`? – Shaw Mar 22 '12 at 00:11
  • 1
    @Shaw: The `m.length - 1` is because the `"00000"` string doesn't have an extra unused zero, it's only as long as needed. As `m` is always at least one character long, you only need five zeroes to pad it, and when `m.length` is 1, `m.length - 1` gives you 0, which is the starting position in the string to return all five zeroes. You could use `"000000".substr(m.length)`, i.e. the length of the string is the number of digits that you want, but then the first character of the string is just dummy padding, it's never used. – Guffa Mar 22 '12 at 07:21
3

http://jsfiddle.net/hHfUC/1/

The regex is pretty simple, just pass the patched digits to a function, and return the modified match as replacement.

"abc8 23 123".replace(/\d+/g,function(x){ return zeroFill(parseInt(x),6) })

Requred zeroFill function

function zeroFill( number, width ){
  if ( number.toString().length >= width )
    return number;
  return ( new Array( width ).join( '0' ) + number.toString() ).substr( -width );
}
Billy Moon
  • 57,113
  • 24
  • 136
  • 237
  • Great, though Guffa's answer is simpler/faster for my use. Thank you for taking your time to answer my question. – Shaw Mar 22 '12 at 00:12
  • Yes, his answer is simpler. It also cuts off numbers longer than the padding. If that is not an issue then use and abuse it ,~) – Billy Moon Mar 22 '12 at 09:25
1

Or... yanno...

("0000"+var).slice(-4); // Normal old JS `0000${var}`.slice(-4); // Sexier JS

The first evaluation coerces our variable var into a string literal, prepending n 0's to it (so for a value of 123 we wind up with "0000123", then the slice starting from the end of the string (the negative modifier) counts backwards n character (so "0000123" or "0123").

The lovely part here is I can define a global constant (const ZedsPadBabyZedsPad='00000000000000';) which is then usable for pretty much ANY typical lead-padding application, from 5-digit image number (img00011.jpg) to date (02/01/04) to (military) time: (07:00).

Don't want 0's? s'cool. STRING, baby. `WhatACROCK${'you'}`.slice(-4) // 'ROCKyou'

ZenAtWork
  • 91
  • 1
  • 8
0

Slightly improve @Guffa's anwser:

Now you can specify the total length after padding zero by given total_length parameter.

function addLeadingZero(str, total_length = 4) {
  const leading_zeros = '0'.repeat(total_length)
  str = str.replace(/\d+/g, function(m) {
    return leading_zeros.substr(m.length) + m
  })
  return str
}

console.log(addLeadingZero("abc8 23 123", 0))
console.log(addLeadingZero("abc8 23 123", 5))
console.log(addLeadingZero("abc8 23 123", 6))
allenyllee
  • 964
  • 1
  • 13
  • 16