2

I have a single line string of length n, which I want to split into maximum of 3 lines. Each line can have a maximum of 45 chars, after which I want to add a new-line char ("\n"). The 3rd line can have a maximum of 42 chars after which I need to include 3 dots (...) if the string goes beyond that, thus making the total characters in the 3rd line 45 as well.

The condition is that the new line character should not be added in the middle of a word. How do I do this efficiently? This operation is just a small part of the entire program, but will be called repeatedly. So I'm not sure if I should actually bother about the efficiency.

What I'm doing right now is that I first figure out where the spaces between words are and then add it to a List. I then iterate through the list and find 3 indices each representing the end word of each line. So the first index will be the space closest to 45, the next closest to 90, and the third closest to 135. I then use these indices to split the actual string, and add "\n" and "..." respectively. This is my code:

//maxCharsPerLine will be 45 public String splitString(String input, int maxCharsPerLine){ String output = ""; ArrayList<Integer> spaces = new ArrayList<Integer>(); // Logic to figure out after which word the sentence should be split so that we don't split in middle of a word for(int index = 0; index < input.length(); index++){ if(input.charAt(index)==' '){ spaces.add(index); } } //add index of last word of string spaces.add(input.length()); int index1 = 0; int index2 = 0; int index3 = 0; for(Integer index : spaces){ // find word closest to and less than maxCharsPerLine. This index will be used to find the last word in line1 if(index<=maxCharsPerLine) index1 = index; // find word closest to and less than 2*maxCharsPerLine. This index will be used to find the last word in line2 else if(index<=2*maxCharsPerLine) index2 = index; // find word closest to and less than 3*maxCharsPerLine, but exclude 3 chars for adding the dots (...). This index will be used to find the last word in line3 else if(index<=(3*maxCharsPerLine)-3) index3 = index; } if(input.length()>maxCharsPerLine){ if(index1 > 0) output = input.substring(0, index1); if(index2 > 0) output += "\n"+input.substring(index1+1, index2); if(index3 > 0){ output += "\n"+input.substring(index2+1, index3); if(input.length()>3*maxCharsPerLine) output += "..."; } } //if length of input is < 45, just return the input else output = input; return output; } 

Not sure in which scenarios this will fail. Is there a better way to do this?

Thanks.

2
  • 1
    Some points: (a) If there is a long word around the 45th char, you may get your first index at, say, 39. Then your second line might end up being around 50 characters long, as you cut it at exactly at 90. (b) Sometimes there may be more than one consecutive space. (c) I would generalize this in case in the future you'll want 4 or 5 lines. (d) Consider using lastIndexOf(String,int). Commented Sep 16, 2015 at 9:56
  • possible duplicate of Large string split into lines with maximum length in java Commented Sep 16, 2015 at 9:56

5 Answers 5

8

You can use WordUtils.wrap method of Apache Commans Lang if 3 dots are not be considered for wrapping the line.

WordUtils.wrap(str, 45)

Sign up to request clarification or add additional context in comments.

2 Comments

Sure. It's all yours. :)
I just used this and modified it a bit to make it work for me. Thanks.
1

Code

public class test3 { public static void main(String[] args) { String S = "The condition is that the new line should not be added in the middle of a word. How do I do this efficiently? This operation is just a small part of the entire program, but will be called repeatedly. So I'm not sure if I should actually bother about the efficiency"; String Op = ""; String Op1 = ""; String Op2 = ""; String Op3 = ""; String Temp[] = S.split(" "); int max_size_1 = 45; int max_size_2 = 45; int max_size_3 = 42; int length = 0; for (int i = 0; i < Temp.length; i++) { length = length + Temp[i].length()+1; if(length <= max_size_1) Op1 = Op1 + Temp[i]+" "; else if(length <= Op1.length()+max_size_2) Op2 = Op2 +Temp[i]+" "; else if(length <= Op1.length()+Op2.length()+max_size_3) Op3 = Op3 + Temp[i]+" "; else {Op3 = Op3 +'\b' + "..."; i =Temp.length ; } //backspace } Op = Op1+"\n"+Op2+"\n"+Op3; System.out.println(Op); System.out.println(Op1.length()+" "+Op2.length()+" "+Op3.length()+" "); }} 

Output

The condition is that the new line should not be added in the middle of a word. How do I do this efficiently? This operation... 42 45 45 

Comments

0

Here another solution, though it might be corrupted and needs to be edited.

int sizeOfString = input.lenght(); //the maximum lenght of a String int aPartialStringLenght = 45; String firstString; String secondString; String thirdString; for(int x = 1; x <= 3; x++){ // looks for the last space before your 45th character //sets the lenght for the third String to max. 42characters if(x == 3){ aPartialStringLenght = 42; } while(!input.charAt(aPartialStringLenght*x).equals(" ")){ aPartialStringLenght -=1; } switch(x){ // gets the substring till your first partialString case 1: firstString = input.substring(0, aPartialStringlenght); aPartialStringLenght = 45; // gets the substring from the end of your first partialString till the end of your second partialString case 2: secondString = input.substring(firstString.lenght(), aPartialStringLenght + firstString.lenght()); aPartialStringLenght = 45; // gets the substring from the end of your second partialString till till the end of your third partialString + "..." case 3 thirdString = input.substring(firstString.lenght()+secondString.lenght(), aPartialStringLenght + firstString.lenght()+ secondString.lenght() )+"..." aPartialStringLenght = 45; } } 

Comments

0

Based on surya answer

 public class test3 { public static void main(String[] args) { String S = "The condition is that the new line should not be added in the middle of a word. How do I do this efficiently? This operation is just a small part of the entire program, but will be called repeatedly. So I'm not sure if I should actually bother about the efficiency"; String F = WordUtils.wrap(S, 45); String[] F1 = F.split(System.lineSeparator()); System.out.println(F1[0]); System.out.println(F1[1]); F1[2] = F1[2] +'\b'+'\b'+'\b'+"..."; System.out.println(F1[2]); } } 

Output

The condition is that the new line should not be added in the middle of a word. How do I do this efficiently? This operation is jus... 

Comments

0

My proposal is highly efficient, because:

  • It needs just two objects: the final string and a temporary StringBuilder, which is pre-sized,
  • And it does not waste time in pre-processing: Processes each character just once, and decides on the fly what to do.

And it is also flexible, because all the involved data are received as parameters:

public final class LinesSplitter { private LinesSplitter(){} private static final char NL='\n'; public static String splitInLines(String text, int maxLineLength, int maxLines, String lastLineSuffix) { StringBuilder output=new StringBuilder((1 + maxLineLength) * maxLines); int p=0; int startOfLine=0; int lastBlank=0; int lastNonBlank=0; int len=text.length(); String neededSuffix=text.length() > maxLineLength * maxLines ? lastLineSuffix : ""; int lines=0; while (lines < maxLines && p < len) { char c=text.charAt(p); if (Character.isWhitespace(c)) { lastBlank=p; lastNonBlank=1 + p; } else if (p < len) { int maxLengthForCurrentLine=getMaxLength(maxLineLength, maxLines, 1 + lines, neededSuffix); if (p - startOfLine == maxLengthForCurrentLine) { output.append(text, startOfLine, lastBlank); String suffix=getSuffix(maxLineLength, maxLines, 1 + lines, neededSuffix); if (!suffix.isEmpty()) { output.append(suffix); } else { output.append(NL); } lines++; startOfLine=lastNonBlank; } } p++; } if (lines < maxLines && p - startOfLine > 0) { output.append(text, startOfLine, len); } return output.toString(); } private final static int getMaxLength(int maxLineLength, int maxLines, int currentLine, String lastLineSuffix) { return currentLine == maxLines ? maxLineLength - lastLineSuffix.length() : maxLineLength; } private final static String getSuffix(int maxLineLength, int maxLines, int currentLine, String lastLineSuffix) { return currentLine == maxLines ? lastLineSuffix : ""; } } 

The only possible drawback is that it does not support several adjacent blanks.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.