Reputation: 57209
As the title says, I've got a string and I want to split into segments of n characters.
For example:
var str = 'abcdefghijkl';
after some magic with n=3
, it will become
var arr = ['abc','def','ghi','jkl'];
Is there a way to do this?
Upvotes: 323
Views: 307776
Reputation: 1
This questions even in 2025 seems to be very interesting challenge!
My solution with ES6 syntax:
let str = 'abcdefghijklm';
let chs = [...str];
let arr = [];
let a, b, c;
while (chs.length) {
([a, b, c, ...chs] = chs);
let abc = [a, b, c].join('');
arr.push(abc);
}
console.log('arr', arr);
Upvotes: 0
Reputation: 53
Here is another solution to this using reduce:
function chunkString(sStr, iLen) {
return [...sStr].reduce((aChunks, sChar, iIdx) => (
aChunks.push(iIdx % iLen === 0 ? sChar : aChunks.pop() + sChar), aChunks), [])
}
This works by splitting the string into an array of characters, and pushing a new entry to the list when the index points to a number that's a remainder of iLen
, and when not, puts the character at the end of the last entry in the array.
Example usage:
// Proper groups
chunkString('abcdefghijkl', 3) // => ['abc', 'def', 'ghi', 'jkl' ]
// Improper groups
chunkString('abcdefghijklmn', 3) // => [ 'abc', 'def', 'ghi', 'jkl', 'mn' ]
// Get rid of improper groups using a filter:
chunkString('abcdefghijklmn', 3)
.filter(entry => entry.length === 3) // => [ 'abc', 'def', 'ghi', 'jkl' ]
Upvotes: 0
Reputation: 99960
Here we intersperse a string with another string every n characters:
export const intersperseString = (n: number, intersperseWith: string, str: string): string => {
let ret = str.slice(0,n), remaining = str;
while (remaining) {
let v = remaining.slice(0, n);
remaining = remaining.slice(v.length);
ret += intersperseWith + v;
}
return ret;
};
if we use the above like so:
console.log(intersperseString(3, '|', 'aagaegeage'));
we get:
aag|aag|aeg|eag|e
and here we do the same, but push to an array:
export const sperseString = (n: number, str: string): Array<string> => {
let ret = [], remaining = str;
while (remaining) {
let v = remaining.slice(0, n);
remaining = remaining.slice(v.length);
ret.push(v);
}
return ret;
};
and then run it:
console.log(sperseString(5, 'foobarbaztruck'));
we get:
[ 'fooba', 'rbazt', 'ruck' ]
if someone knows of a way to simplify the above code, lmk, but it should work fine for strings.
Upvotes: 1
Reputation: 490143
If you didn't want to use a regular expression...
var str = 'abcdefghijkl';
var chunks = [];
for (var i = 0, charsLength = str.length; i < charsLength; i += 3) {
chunks.push(str.substring(i, i + 3));
}
console.log(chunks);
...otherwise the regex solution is pretty good :)
Upvotes: 76
Reputation: 1
function groupChars(str = "ABCDEFGHI",inGroupsOf = 3){
let groups = [];
for (let i = 0; i < str.length; i++) {
(i%inGroupsOf) == 0 ? groups.push(str.slice(i,inGroupsOf + i)):null
}
return groups;
}
console.log(groupChars("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
The function groupChars
takes two arguments - str
and inGroupsOf
.
The inGroupsOf
parameter determines the number of characters each group is to be made of.
let groups = [];
for
loopinGroupsOf
argument is zero: ( i % inGroupsOf) == 0;
Upvotes: 0
Reputation: 5641
I was looking for a solution to convert a number like 1000000
to 1,000,000
and I definitely don't want to keep running heavy Regex operations, slowing down my code.
Alex's solution was perfect (among all the regex based solutions!). I've modified and wrapped that up into a function that can format a number into thousand-separated number:
function thouSep(str, delim=","){
var chunks = [];
str+=""
for (var i = str.length; i >0; i -= 3) {
chunks.push(str.substring(i-3, i));
}
f = chunks.reverse().join(delim)
return f
}
Usage:
thouSep(100000) => "100,000"
thouSep(10000) => "10,000"
thouSep(10) => "10"
thouSep(1000000) => "1,000,000"
thouSep("Fabulous", "-") => "Fa-bul-ous"
Possible improvements:
12345.6789
=> 12,345.6789
Upvotes: 0
Reputation: 1
var b1 = "";
function myFunction(n) {
if(str.length>=3){
var a = str.substring(0,n);
b1 += a+ "\n"
str = str.substring(n,str.length)
myFunction(n)
}
else {
if(str.length>0){
b1 += str
}
console.log(b1)
}
}
myFunction(4)
Upvotes: -1
Reputation: 1176
var str = 'abcdefghijkl';
var res = str.match(/.../g)
console.log(res)
here number of dots determines how many text you want in each word.
Upvotes: 7
Reputation: 27300
Here's a way to do it without regular expressions or explicit loops, although it's stretching the definition of a one liner a bit:
const input = 'abcdefghijlkm';
// Change `3` to the desired split length.
const output = input.split('').reduce((s, c) => {
let l = s.length-1;
(s[l] && s[l].length < 3) ? s[l] += c : s.push(c);
return s;
}, []);
console.log(output); // output: [ 'abc', 'def', 'ghi', 'jlk', 'm' ]
It works by splitting the string into an array of individual characters, then using Array.reduce
to iterate over each character. Normally reduce
would return a single value, but in this case the single value happens to be an array, and as we pass over each character we append it to the last item in that array. Once the last item in the array reaches the target length, we append a new array item.
Upvotes: 2
Reputation:
function str_split(string, length = 1) {
if (0 >= length)
length = 1;
if (length == 1)
return string.split('');
var string_size = string.length;
var result = [];
for (let i = 0; i < string_size / length; i++)
result[i] = string.substr(i * length, length);
return result;
}
str_split(str, 3)
Upvotes: 0
Reputation: 479
My favorite answer is gouder hicham's. But I revised it a little so that it makes more sense to me.
let myString = "Able was I ere I saw elba";
let splitString = [];
for (let i = 0; i < myString.length; i = i + 3) {
splitString.push(myString.slice(i, i + 3));
}
console.log(splitString);
Here is a functionalized version of the code.
function stringSplitter(myString, chunkSize) {
let splitString = [];
for (let i = 0; i < myString.length; i = i + chunkSize) {
splitString.push(myString.slice(i, i + chunkSize));
}
return splitString;
}
And the function's use:
let myString = "Able was I ere I saw elba";
let mySplitString = stringSplitter(myString, 3);
console.log(mySplitString);
And it's result:
>(9) ['Abl', 'e w', 'as ', 'I e', 're ', 'I s', 'aw ', 'elb', 'a']
Upvotes: 4
Reputation: 91
If you really need to stick to .split
and/or .raplace
, then use /(?<=^(?:.{3})+)(?!$)/g
For .split
:
var arr = str.split( /(?<=^(?:.{3})+)(?!$)/ )
// [ 'abc', 'def', 'ghi', 'jkl' ]
For .replace
:
var replaced = str.replace( /(?<=^(?:.{3})+)(?!$)/g, ' || ' )
// 'abc || def || ghi || jkl'
/(?!$)/
is to not stop at end of the string. Without it's:
var arr = str.split( /(?<=^(?:.{3})+)/ )
// [ 'abc', 'def', 'ghi', 'jkl' ] // is fine
var replaced = str.replace( /(?<=^(.{3})+)/g, ' || ')
// 'abc || def || ghi || jkl || ' // not fine
Ignoring group /(?:
...)/
is to prevent duplicating entries in the array. Without it's:
var arr = str.split( /(?<=^(.{3})+)(?!$)/ )
// [ 'abc', 'abc', 'def', 'abc', 'ghi', 'abc', 'jkl' ] // not fine
var replaced = str.replace( /(?<=^(.{3})+)(?!$)/g, ' || ' )
// 'abc || def || ghi || jkl' // is fine
Upvotes: 9
Reputation: 133
try this simple code and it will work like magic !
let letters = "abcabcabcabcabc";
// we defined our variable or the name whatever
let a = -3;
let finalArray = [];
for (let i = 0; i <= letters.length; i += 3) {
finalArray.push(letters.slice(a, i));
a += 3;
}
// we did the shift method cause the first element in the array will be just a string "" so we removed it
finalArray.shift();
// here the final result
console.log(finalArray);
Upvotes: 2
Reputation: 313
Coming a little later to the discussion but here a variation that's a little faster than the substring + array push one.
// substring + array push + end precalc
var chunks = [];
for (var i = 0, e = 3, charsLength = str.length; i < charsLength; i += 3, e += 3) {
chunks.push(str.substring(i, e));
}
Pre-calculating the end value as part of the for loop is faster than doing the inline math inside substring. I've tested it in both Firefox and Chrome and they both show speedup.
You can try it here
Upvotes: 1
Reputation: 31
const chunkStr = (str, n, acc) => {
if (str.length === 0) {
return acc
} else {
acc.push(str.substring(0, n));
return chunkStr(str.substring(n), n, acc);
}
}
const str = 'abcdefghijkl';
const splittedString = chunkStr(str, 3, []);
Clean solution without REGEX
Upvotes: 3
Reputation: 411
My solution (ES6 syntax):
const source = "8d7f66a9273fc766cd66d1d";
const target = [];
for (
const array = Array.from(source);
array.length;
target.push(array.splice(0,2).join(''), 2));
We could even create a function with this:
function splitStringBySegmentLength(source, segmentLength) {
if (!segmentLength || segmentLength < 1) throw Error('Segment length must be defined and greater than/equal to 1');
const target = [];
for (
const array = Array.from(source);
array.length;
target.push(array.splice(0,segmentLength).join('')));
return target;
}
Then you can call the function easily in a reusable manner:
const source = "8d7f66a9273fc766cd66d1d";
const target = splitStringBySegmentLength(source, 2);
Cheers
Upvotes: 4
Reputation: 20132
Some clean solution without using regular expressions:
/**
* Create array with maximum chunk length = maxPartSize
* It work safe also for shorter strings than part size
**/
function convertStringToArray(str, maxPartSize){
const chunkArr = [];
let leftStr = str;
do {
chunkArr.push(leftStr.substring(0, maxPartSize));
leftStr = leftStr.substring(maxPartSize, leftStr.length);
} while (leftStr.length > 0);
return chunkArr;
};
Usage example - https://jsfiddle.net/maciejsikora/b6xppj4q/.
I also tried to compare my solution to regexp one which was chosen as right answer. Some test can be found on jsfiddle - https://jsfiddle.net/maciejsikora/2envahrk/. Tests are showing that both methods have similar performance, maybe on first look regexp solution is little bit faster, but judge it Yourself.
Upvotes: 0
Reputation: 93664
var str = 'abcdefghijkl';
console.log(str.match(/.{1,3}/g));
Note: Use {1,3}
instead of just {3}
to include the remainder for string lengths that aren't a multiple of 3, e.g:
console.log("abcd".match(/.{1,3}/g)); // ["abc", "d"]
A couple more subtleties:
.
won't capture those. Use /[\s\S]{1,3}/
instead. (Thanks @Mike).match()
will return null
when you may be expecting an empty array. Protect against this by appending || []
.So you may end up with:
var str = 'abcdef \t\r\nghijkl';
var parts = str.match(/[\s\S]{1,3}/g) || [];
console.log(parts);
console.log(''.match(/[\s\S]{1,3}/g) || []);
Upvotes: 565
Reputation: 939
function chunk(er){
return er.match(/.{1,75}/g).join('\n');
}
Above function is what I use for Base64 chunking. It will create a line break ever 75 characters.
Upvotes: 1
Reputation: 48600
Building on the previous answers to this question; the following function will split a string (str
) n-number (size
) of characters.
function chunk(str, size) {
return str.match(new RegExp('.{1,' + size + '}', 'g'));
}
(function() {
function chunk(str, size) {
return str.match(new RegExp('.{1,' + size + '}', 'g'));
}
var str = 'HELLO WORLD';
println('Simple binary representation:');
println(chunk(textToBin(str), 8).join('\n'));
println('\nNow for something crazy:');
println(chunk(textToHex(str, 4), 8).map(function(h) { return '0x' + h }).join(' '));
// Utiliy functions, you can ignore these.
function textToBin(text) { return textToBase(text, 2, 8); }
function textToHex(t, w) { return pad(textToBase(t,16,2), roundUp(t.length, w)*2, '00'); }
function pad(val, len, chr) { return (repeat(chr, len) + val).slice(-len); }
function print(text) { document.getElementById('out').innerHTML += (text || ''); }
function println(text) { print((text || '') + '\n'); }
function repeat(chr, n) { return new Array(n + 1).join(chr); }
function textToBase(text, radix, n) {
return text.split('').reduce(function(result, chr) {
return result + pad(chr.charCodeAt(0).toString(radix), n, '0');
}, '');
}
function roundUp(numToRound, multiple) {
if (multiple === 0) return numToRound;
var remainder = numToRound % multiple;
return remainder === 0 ? numToRound : numToRound + multiple - remainder;
}
}());
#out {
white-space: pre;
font-size: 0.8em;
}
<div id="out"></div>
Upvotes: 20