11

How do we split a string every 3 characters from the back using JavaScript?

Say, I have this:

str = 9139328238

after the desired function, it would become:

parts = ['9','139','328','238']

How do we do this elegantly?

1

9 Answers 9

21
var myString = String( 9139328238 );
console.log( myString.split( /(?=(?:...)*$)/ ) );
// ["9", "139", "328", "238"]

I can't make any performance guarantees. For smallish strings it should be fine.

Here's a loop implementation:

function funkyStringSplit( s )
{
    var i = s.length % 3;
    var parts = i ? [ s.substr( 0, i ) ] : [];
    for( ; i < s.length ; i += 3 )
    {
        parts.push( s.substr( i, 3 ) );
    }
    return parts;
}
10
  • 8
    You should use a non-capturing group to generate the desired output: /(?=(?:...)*$)/ Commented Feb 7, 2013 at 13:13
  • How does it matter wether I capture or not? it's splitting, not using captures.
    – Alex
    Commented Feb 7, 2013 at 13:18
  • @Ales: Well, ["9", "238", "139", "238", "328", "238", "238"] does not look like the result the OP wants. And it's hard to see how to get from there to what the OP wants. Commented Feb 7, 2013 at 13:19
  • 2
    I was using a different string in my console... let me edit that... --- turns out I wasn't. Thanks Felix!
    – Alex
    Commented Feb 7, 2013 at 13:20
  • Also, you probably want to start the regex with \B in case the number of digits is divisible by three (and use + instead of * for clarity). Commented Feb 7, 2013 at 13:28
4

I know this is an old question, but I would like to provide my own one-line version to solve the problem :)

"12345678".split('').reverse().join('').match(/.{1,3}/g).map(function(x){
    return x.split('').reverse().join('')
}).reverse()

This basically reverses the string, captures the groups of 3 elements, reverses each group and then reverses the whole string.

The steps are:

"12345678" -> [1, 2, 3, 4, 5, 6, 7, 8] //.split('')
[1, 2, 3, 4, 5, 6, 7, 8] -> [8, 7, 6, 5, 4, 3, 2, 1] //.reverse()
[8, 7, 6, 5, 4, 3, 2, 1] -> "87654321" //.join('')
"87654321" -> [876, 543, 21] //.match(...)
[876, 543, 21] -> [678, 345, 12] //.map(function(x){...})
[678, 345, 12] -> [12, 345, 678] //.reverse()

You can then join the array with a character (e.g. the ',' for thousands separator)

[12, 345, 678].join(',') -> "12,345,678"
4

There are a lot of complicated answers here.

function group(value) {
  return value.match(/\d{1,3}(?=(\d{3})*$)/g);
}

console.log(group('1'));
console.log(group('123'));
console.log(group('1234'));
console.log(group('12345'));
console.log(group('123456'));
console.log(group('1234567'));
console.log(group('12345678'));
console.log(group('123456789'));

0

Not as elegant, but shows you a while loop

 function commaSeparateNumber (val) {
    val = val.toString();
    while (/(\d+)(\d{3})/.test(val)){
      val = val.replace(/(\d+)(\d{3})/, '$1'+','+'$2');
    }
    return val;
  }

  var str = "9139328238";
  var splitStr = commaSeparateNumber(str).split(",");
  console.log(splitStr);
0

Try this:

var str = 9139328238 + ''; //convert int to string
var reqArr = []; // required array
var len = str.length; //maintaining length
while (len > 0) {
    len -= 3;
    reqArr.unshift(str.slice(len)); //inserting value to required array
    str = str.slice(0, len); //updating string
}

Hope it helps..

0

Since regex operations are not liked by everyone for various reasons: here is a regular function using a regular loop to split any regular string every X characters from back. Nothing fancy but it works:

function splitStringFromEnd(customString, every) {
  var result = [], counter = every;
  // loop that captures substring chungs of "every" length e.g.: 1000.00 -> ["000", ".00"]
  for (var i = counter; counter <= customString.length; counter += every) {
    result.unshift(customString.substr(customString.length - counter, every))
  }
  // check if there is a remainder and grabs it.
  // Using our 1000.00 example: diff = 9 - 7; remainder = 3 - 2; -> ["1", "000", ".00"]
  var diff = counter - customString.length;
  var remainder = every - diff;
  if(remainder > 0) { result.unshift(customString.substr(0, remainder)) }
  return result;
}

for your example it would be:

splitStringFromEnd("9139328238", 3);
// :returns => ["9", "139", "328", "238"]

Enjoy :)

0
const price_format = (price) => {
    let result = [];
    let new_str = [...price].reverse().join("");
    let rightSplit = new_str.match(/.{1,3}/g).reverse();
    for (let item of rightSplit) {
        result.push([...item].reverse().join(""));
    }
    return result.join(",");
}
let price = "2560000000";
console.log(price_format(price));

// output : 2,560,000,000
0

"12345678".split('').reverse().reduce((a, s) => (a[0].length<3?a[0]=s+a[0]:a.unshift(s),a), ['']);

2
  • 1
    While the answer is correct, we encourage people to provide context and explain as much as possible the proposed solution. This way we all can learn together and understand better.
    – Jair Reina
    Commented Mar 30, 2022 at 15:19
  • 1
    Welcome to SO! Consider providing supporting information to explain your answer. Commented Apr 1, 2022 at 17:39
-2

Finally it seems good. This is what I have got till now without using any loops

function breakAt3(x)
    {
            if(x.length < 3){ var parts = [x]; return parts; }
        var startPos = (x.length % 3);
        var newStr = x.substr(startPos); 
        var remainingStr = x.substr(0,startPos); 

        var parts = newStr.match(/.{1,3}/g);
        if(remainingStr != ''){ var length = parts.unshift(remainingStr); }
        return parts;

    }

    var str = '92183213081';  
    var result = breakAt3(str);  // 92,183,213,081 
3
  • A +1 for @Alex. He was really quick. Commented Feb 7, 2013 at 13:36
  • this solution doesn't work for strings with length < 3, and returns an additional empty string for strings of length 3. The problem is the match at line 7 can fail.
    – Alex
    Commented Feb 7, 2013 at 13:39
  • 1
    Now strings with length < 3 don't return an array anymore! There's something wrong with your logic. You're assigning into a new var length and never using it.
    – Alex
    Commented Feb 7, 2013 at 13:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.