16

Good day,

I would like to know if there is an easy way to chunk/split a string without breaking the words.

Eg:

var input = "Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Proin placerat, nisi nec vulputate scelerisque, metus lectus ultricies massa, et luctus elit libero eu erat. Fusce vitae sem lacus, eu ullamcorper lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

Should return an array like this if I break at 80 characters long:

var output = ["Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Proin placerat, nisi",
"nec vulputate scelerisque, metus lectus ultricies massa, et luctus elit libero",
"eu erat. Fusce vitae sem lacus, eu ullamcorper lectus. Lorem ipsum dolor sit",
"amet, consectetur adipiscing elit."];

I found that really nice piece of code:

//http://phpjs.org/functions/chunk_split:369
function chunk_split (body, chunklen, end) {
    // Returns split line  
    // 
    // version: 1103.1210
    // discuss at: http://phpjs.org/functions/chunk_split
    // +   original by: Paulo Freitas
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Theriault
    // *     example 1: chunk_split('Hello world!', 1, '*');
    // *     returns 1: 'H*e*l*l*o* *w*o*r*l*d*!*'
    // *     example 2: chunk_split('Hello world!', 10, '*');
    // *     returns 2: 'Hello worl*d!*'
    chunklen = parseInt(chunklen, 10) || 76;
    end = end || '\r\n';

    if (chunklen < 1) {
        return false;
    }

    return body.match(new RegExp(".{0," + chunklen + "}", "g")).join(end);
}

But I really doubt I can modify it so words aren't broken in half. Any tips?

Thank you!

Cybrix
  • 3,248
  • 5
  • 42
  • 61
  • strings are arrays so you can test if string[80] is a character (not a space) if yes then 81,82 .... and so on – Ibu Jul 09 '11 at 03:34

4 Answers4

14

Here's some brute force code that will do it:

function splitIntoLines(input, len) {
    var i;
    var output = [];
    var lineSoFar = "";
    var temp;
    var words = input.split(' ');
    for (i = 0; i < words.length;) {
        // check if adding this word would exceed the len
        temp = addWordOntoLine(lineSoFar, words[i]);
        if (temp.length > len) {
            if (lineSoFar.length == 0) {
                lineSoFar = temp;     // force to put at least one word in each line
                i++;                  // skip past this word now
            }
            output.push(lineSoFar);   // put line into output
            lineSoFar = "";           // init back to empty
        } else {
            lineSoFar = temp;         // take the new word
            i++;                      // skip past this word now
        }
    }
    if (lineSoFar.length > 0) {
        output.push(lineSoFar);
    }
    return(output);
}

function addWordOntoLine(line, word) {
    if (line.length != 0) {
        line += " ";
    }
    return(line += word);
}

If this routine encounters a single word longer than the desired line length, it will put it on a line by itself and will not break it up.

You can play with it here: http://jsfiddle.net/jfriend00/fbaLe/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
9

This builds on @steve's answer but will split the string respecting word break so that the string is never longer than the specified length. This works more like a normal word wrap.

function chunkString(s, len)
{
    var curr = len, prev = 0;

    output = [];

    while(s[curr]) {
      if(s[curr++] == ' ') {
        output.push(s.substring(prev,curr));
        prev = curr;
        curr += len;
      }
      else
      {
        var currReverse = curr;
        do {
            if(s.substring(currReverse - 1, currReverse) == ' ')
            {
                output.push(s.substring(prev,currReverse));
                prev = currReverse;
                curr = currReverse + len;
                break;
            }
            currReverse--;
        } while(currReverse > prev)
      }
    }
    output.push(s.substr(prev)); 
    return output;
}
orourkedd
  • 6,201
  • 5
  • 43
  • 66
8

Thank to orourkedd, it iwas very useful. I just updated it with splitting.

private chunkString(str, len) {
    let input = str.trim().split(' ');
    let [index, output] = [0, []]
    output[index] = '';
    input.forEach(word => {
        let temp = `${output[index]} ${word}`.trim()
        if (temp.length <= len) {
            output[index] = temp;
        } else {
            index++;
            output[index] = word;
        }
    })
    return output
}
Eriixon
  • 81
  • 1
  • 1
8

Something like this?

var n = 80;

while (n) { 
    if (input[n++] == ' ') { 
        break;  
    } 
}

output = input.substring(0,n).split(' ');
console.log(output);

UPDATED

Now that I re-read the question, here's an updated solution:

var len = 80;
var curr = len;
var prev = 0;

output = [];

while (input[curr]) {
    if (input[curr++] == ' ') {
        output.push(input.substring(prev,curr));
        prev = curr;
        curr += len;
    }
}
output.push(input.substr(prev));  
Ben
  • 54,723
  • 49
  • 178
  • 224
  • When I saw your small piece of codes I was happy for such a small way to do it. Unfortunatly I can't make it work. – Cybrix Jul 09 '11 at 16:19
  • Sorry, I misunderstood your question. :( Modified my answer though and it's still small. :) – Ben Jul 11 '11 at 04:35
  • not sure what i'm missing here but this doesn't break as requested – kman Jul 26 '12 at 04:35
  • Thank you, I'd tried to find something similar. Currently working with google apps-script, and it's haven't css :( – Sumskyi Vasyl Jun 16 '21 at 13:02