Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I split a string into segments of n characters?

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?

like image 489
Ben Avatar asked Jun 07 '11 00:06

Ben


People also ask

How do I split a string into multiple strings?

split() The method split() splits a String into multiple Strings given the delimiter that separates them. The returned object is an array which contains the split Strings. We can also pass a limit to the number of elements in the returned array.


13 Answers

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:

  1. If your string may contain newlines (which you want to count as a character rather than splitting the string), then the . won't capture those. Use /[\s\S]{1,3}/ instead. (Thanks @Mike).
  2. If your string is empty, then 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) || []);
like image 158
David Tang Avatar answered Oct 05 '22 22:10

David Tang


If you didn't want to use a regular expression...

var chunks = [];

for (var i = 0, charsLength = str.length; i < charsLength; i += 3) {
    chunks.push(str.substring(i, i + 3));
}

jsFiddle.

...otherwise the regex solution is pretty good :)

like image 29
alex Avatar answered Oct 05 '22 23:10

alex


str.match(/.{3}/g); // => ['abc', 'def', 'ghi', 'jkl']
like image 34
maerics Avatar answered Oct 06 '22 00:10

maerics


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

Demo

(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>
like image 20
Mr. Polywhirl Avatar answered Oct 05 '22 23:10

Mr. Polywhirl


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
like image 25
denisde4ev Avatar answered Oct 05 '22 23:10

denisde4ev


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

like image 44
Jesus Gonzalez Avatar answered Oct 05 '22 23:10

Jesus Gonzalez


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

like image 25
seriouspat Avatar answered Oct 05 '22 22:10

seriouspat


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);
like image 44
gouder hicham Avatar answered Oct 05 '22 23:10

gouder hicham


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']
like image 45
garydavenport73 Avatar answered Oct 06 '22 00:10

garydavenport73


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.

like image 40
Dave Brown Avatar answered Oct 05 '22 23:10

Dave Brown


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

like image 25
Alexander Mills Avatar answered Oct 05 '22 22:10

Alexander Mills


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.

like image 28
Malvineous Avatar answered Oct 05 '22 23:10

Malvineous


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

like image 45
Dragonaire Avatar answered Oct 06 '22 00:10

Dragonaire