Split string in array on whitespace before the 10th character

Viewed 509

I want to split a string into characters of 10. But I don't want to split inside a word.

So the string "Nine characters to go - then some more" would be split in ["Nine", "characters", "to go -", "then some", "more"].
The word can split if it's more than 10 characters.

The closest I got using regex was .{1,10}(?<=\s).
That would split "Nine characters to go - then some more" into ["Nine ", "haracters ", "to go - ", "then some "].
But the behaviour is weird. In the example string it completely skips the character "c". In other test strings it would only add "- " in a separate array item when just the dash would fit in with the array item before it. So it splits after the whitespace.

I also attempted to .split() on white spaces (.split(' ')) and using .reduce() or a for loop to join array items into other array items of max 10 characters.

for ( i = 0; i < splitArray.length; i++ ) {
  if ( i === 0 ) {
    // add first word in new array. Doesn't take into account yet that word can be longer than 10 characters
    newArray.push( splitArray[i] );
  } else {
    if ( newArray[ newArray.length - 1 ].length + splitArray[i].length + 1 < 10 ) {
      // if next word fits with the word in the new array (taking space into account), add it to it
      newArray[ newArray.length - 1 ] = newArray[ newArray.length - 1 ] + " " + splitArray[i];
    } else if ( newArray[ newArray.length - 1 ].length + splitArray[i].length + 1 >= 10 ) {
      // next word doesn't fit
      // split word and add only part to it and add the rest in separate item in newArray
      const index = 9 - newArray[ newArray.length - 1 ].length
      const prev = splitArray[i].slice( 0, index );
      const next = splitArray[i].slice( index, splitArray[i].length );
      newArray[ newArray.length - 1 ] = newArray[ newArray.length - 1 ] + " " + prev;
      newArray.push( next );
    } else {
      // push new item in newArray
      newArray.push( splitArray[i] );
    }
  }
}

Results in: ["Nine chara", "cters to g", "o - then s", "ome more"].
Without the else if: ["Nine", "characters", "to go -", "then some", "more"]
Without the else if other string: ["Paul van", "den Dool", "-", "Alphabet", "- word"]
This is close, but "Alphabet" won't join with the hyphen, because together they don't fit. I tried catching that with an else if statement but that is breaking words again that I don't want to break and is the same result as the regex above.

My mind is depleted on this issue, I need the hive mind for this. So any help on this is very much appreciated.

Context
I'm trying to display text on canvas in a limited sized box with a minimum font size. My solution would be to break the string, which can be entered by the user, into multiple lines if necessary. For this I need to split the string into an array, loop over it and position the text accordingly.

4 Answers

const string = "Nine characters to go - then some more"
let arr = string.split(" ");
for(let i = 1; i < arr.length; i++) {
  if(arr[i].length >= 10 || arr[i].length + arr[i-1].length >= 10) {
     continue;
  }
  if(arr[i].length < 10 && arr[i].length + arr[i-1].length <= 10) {
    arr[i] = arr[i - 1] + " " + arr[i];
    arr[i-1] = false;
  }

}
arr = arr.filter(string => string)

console.log(arr);

Use

console.log(
  "Nine characters to go - then some more"
     .match(/.{1,10}(?=\s|$)/g)
     .map(z => z.trim())
);

With .match(/.{1,10}(?=\s|$)/g), the items will be 1 to 10 characters long, and (?=\s|$) will assure a whitespace or end of string is matched.

If you need to split, use .split():

const str = 'Nine characters to go - then some more',
      
      result = str.split(/(.{1,10})\s/).filter(Boolean)
      
console.log(result)

I can solve this using a simple for loop:

const str = "Nine characters to go - then some more";

// make an array with each words
const arr = str.trim().split(' ');

// This is the length, how much we want to take the length of the words
const length = 10;
const res = [];

/**
 * Put the first word into the result array
 * because if the word greater or less than
 * the `length` we have to take it.
 */
res.push(arr[0]);

// Result array's current index
let index = 0;

for (let i = 1, l = arr.length; i < l; i++) {
  /**
   * If the length of the concatenation of the
   * last word of the result array
   * and the next word is less than or equal to the length
   * then concat them and put them as the last value
   * of the resulting array.
   */
  if ((res[index] + arr[i]).length <= length) {
    res[index] += ' ' + arr[i];
  } else {
    /**
     * Otherwise push the current word
     * into the resulting array
     * and increase the last index of the
     * resulting array.
     */
    res.push(arr[i]);
    index++;
  }
}

console.log(res);
.as-console-wrapper{min-height: 100%!important; top: 0}

Related