0

I have to break up a string field into multiple string fields if the original string exceeds a specific character limit. The original string can be of different lengths but the additional fields like string2, and string3 have a max character length of 10.

Question:

  1. How can I break up a single string field into multiple string fields with defined character limits based on the nearest whitespace to the character limit?

Example:

  1. Hello world, how are you doing?

Assumptions:

  • originalString can be of different string lengths
  • string1 is maxed at 15 characters
  • string2 is maxed at 10 characters
  • string3 is maxed at 10 characters
  • first 15 characters for the originalString would be Hello world, ho
  • next 10 characters would be w are you
  • next 10 character would be doing?
  • Do not break up whole words
  • only populate street2 and street3 if required. if all characters can fit into street1 and street2 then street3 can be empty

What I tried that didn't work:

let originalString = `Hello world, how are you doing?`
if(originalString.length > 15) {
  let string1 = originalString.substring(0,15) // this returns `Hello World,`
  let string2 = ???? // stuck here - need help
  let string3 = ???? // stuck here - need help
}

Expected output:

  • originalString = Hello world, how are you doing?
  • string1 = Hello world,
  • string2 = how are
  • string3 = you doing?
usernameabc
  • 662
  • 1
  • 10
  • 30
  • Are you trying to not break up whole words? I might split up the original string using a space as a delimiter. Test it one word at a time to see if it fits the limits. – mykaf Aug 24 '23 at 18:28
  • @mykaf yes - we don't want to break into a word – usernameabc Aug 24 '23 at 18:43
  • I wonder if something like this question gets you what you need: https://stackoverflow.com/questions/58204155/splitting-a-string-based-on-max-character-length-but-keep-words-into-account I found many variations on Stack Overflow that seem to do exactly what I _think_ you're asking for. – Marc Aug 24 '23 at 18:50

3 Answers3

2

The following will get you what you want:

  • the first string containing up to 15 characters
  • the second string containing up to 10 characters
  • the third string containing up to 10 characters

The breaks will only be done before whitespace characters and never inside a word.

const originalString = `Hello world, how are you doing?`,
      res=originalString.match(/(.{1,15})\s+(.{1,10})\s+(.{1,10})(?:\s+.|$)/);
console.log(res.slice(1));
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
  • what is the reason for `res.slice(1)`? – usernameabc Aug 24 '23 at 20:20
  • the `.match()` is always breaking up the string, but I only want to populate the additional street2 and street3 if needed. How would I be able to update the regex to only populate street3 if there are still characters remaining? – usernameabc Aug 24 '23 at 20:43
  • 1
    The first element of `res` is the original string. I did not want to show it again. Feel free to leave it out. – Carsten Massmann Aug 24 '23 at 20:43
0

I solved this by separating the original string into separate words and incrementally checking the length as I built each string. It works with your example, but could fail if there were some longer words or other written language quirks. I created an array, strings to build each string and indicate its maximum length.

let originalString = `Hello world, how are you doing?`;
let strings = [
    {len:15,string:""},
  {len:10,string:""},
  {len:10,string:""}
];
let originalStringArray = originalString.split(" ");
if(originalString.length > 15) {
    
  let osa_index = 0;
  for (let s = 0; s < strings.length; s++) {
    let proposedString = proposeNewString(s,osa_index);
    
      while (proposedString.length <= strings[s].len) {
        strings[s].string = proposedString;
        osa_index++;
        proposedString = proposeNewString(s,osa_index);
      }
  }
}



console.log(strings.map(s => s.string));

function proposeNewString(s,idx) {
    return (strings[s].string + ' ' + originalStringArray[idx]).trim();
}
mykaf
  • 1,034
  • 1
  • 9
  • 12
0

I haven't tested it for different strings and different line lengths, but you could start from here...

let indices = [];

function getClosest(goal) {
    let find = goal;
    let index;
    let foundAtKey;

    indices.every(function(indice, key){
        if (indice < find && indices[key+1] > find) {
            index = indice;
            foundAtKey = key;

            return false;
        }

        return true;
    });

    indices = indices.slice(foundAtKey + 1);
    indices.forEach(function(value,key){
        indices[key] = value - index;
    });
    return index;
}

function splitString(myString = "Hello world, how are you doing?", indexes = [15, 10, 10]) {
    let myStringArray = [];

    for(let i=0; i < myString.length; i++) {
        if (myString[i] === " ") indices.push(i);
    }

    indexes.forEach(function(index){
        let closest = getClosest(index);

        if(typeof index !== 'undefined'){
            myStringArray.push(myString.substring(0, closest));
            myString = myString.substring(closest);
        } else {
            myStringArray.push(myString);
        }
    });

    return myStringArray;
}

const resultStringArray = splitString(); // or splitString("Hello world, how are you doing?", [15, 10, 10])
console.log(resultStringArray);
poashoas
  • 1,790
  • 2
  • 21
  • 44