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
  • It looks like you are trying to display a number with decimal separator. If so, you better make use of Number.prototype.toLocaleString() native method Commented Feb 27, 2016 at 0:06

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;
}
Sign up to request clarification or add additional context in comments.

10 Comments

You should use a non-capturing group to generate the desired output: /(?=(?:...)*$)/
How does it matter wether I capture or not? it's splitting, not using captures.
@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.
I was using a different string in my console... let me edit that... --- turns out I wasn't. Thanks Felix!
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).
|
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"

Comments

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'));

Comments

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);

Comments

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..

Comments

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 :)

Comments

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

Comments

0

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

2 Comments

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.
Welcome to SO! Consider providing supporting information to explain your answer.
-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 Comments

A +1 for @Alex. He was really quick.
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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.