String input = \"THESE TERMS AND CONDITIONS OF SERVICE (the Terms) ARE A LEGAL AND BINDING AGREEMENT BETWEEN YOU AND NATIONAL GEOGRAPHIC governing your use of this s
Starting from @Barend 's suggestion, following is my final version with minor modifications :
private static final char NEWLINE = '\n';
private static final String SPACE_SEPARATOR = " ";
//if text has \n, \r or \t symbols it's better to split by \s+
private static final String SPLIT_REGEXP= "\\s+";
public static String breakLines(String input, int maxLineLength) {
String[] tokens = input.split(SPLIT_REGEXP);
StringBuilder output = new StringBuilder(input.length());
int lineLen = 0;
for (int i = 0; i < tokens.length; i++) {
String word = tokens[i];
if (lineLen + (SPACE_SEPARATOR + word).length() > maxLineLength) {
if (i > 0) {
output.append(NEWLINE);
}
lineLen = 0;
}
if (i < tokens.length - 1 && (lineLen + (word + SPACE_SEPARATOR).length() + tokens[i + 1].length() <=
maxLineLength)) {
word += SPACE_SEPARATOR;
}
output.append(word);
lineLen += word.length();
}
return output.toString();
}
System.out.println(breakLines("THESE TERMS AND CONDITIONS OF SERVICE (the Terms) ARE A LEGAL AND BINDING " +
"AGREEMENT BETWEEN YOU AND NATIONAL GEOGRAPHIC governing your use of this site, " +
"www.nationalgeographic.com, which includes but is not limited to products, " +
"software and services offered by way of the website such as the Video Player.", 20));
Outputs :
THESE TERMS AND
CONDITIONS OF
SERVICE (the Terms)
ARE A LEGAL AND
BINDING AGREEMENT
BETWEEN YOU AND
NATIONAL GEOGRAPHIC
governing your use
of this site,
www.nationalgeographic.com,
which includes but
is not limited to
products, software
and services
offered by way of
the website such as
the Video Player.
My version(The previous were not working)
public static List<String> breakSentenceSmart(String text, int maxWidth) {
StringTokenizer stringTokenizer = new StringTokenizer(text, " ");
List<String> lines = new ArrayList<String>();
StringBuilder currLine = new StringBuilder();
while (stringTokenizer.hasMoreTokens()) {
String word = stringTokenizer.nextToken();
boolean wordPut=false;
while (!wordPut) {
if(currLine.length()+word.length()==maxWidth) { //exactly fits -> dont add the space
currLine.append(word);
wordPut=true;
}
else if(currLine.length()+word.length()<=maxWidth) { //whole word can be put
if(stringTokenizer.hasMoreTokens()) {
currLine.append(word + " ");
}else{
currLine.append(word);
}
wordPut=true;
}else{
if(word.length()>maxWidth) {
int lineLengthLeft = maxWidth - currLine.length();
String firstWordPart = word.substring(0, lineLengthLeft);
currLine.append(firstWordPart);
//lines.add(currLine.toString());
word = word.substring(lineLengthLeft);
//currLine = new StringBuilder();
}
lines.add(currLine.toString());
currLine = new StringBuilder();
}
}
//
}
if(currLine.length()>0) { //add whats left
lines.add(currLine.toString());
}
return lines;
}
You can use WordUtils.wrap method of Apache Commans Lang
import java.util.*;
import org.apache.commons.lang3.text.WordUtils;
public class test3 {
public static void main(String[] args) {
String S = "THESE TERMS AND CONDITIONS OF SERVICE (the Terms) ARE A LEGAL AND BINDING AGREEMENT BETWEEN YOU AND NATIONAL GEOGRAPHIC governing your use of this site, www.nationalgeographic.com, which includes but is not limited to products, software and services offered by way of the website such as the Video Player, Uploader, and other applications that link to these Terms (the Site). Please review the Terms fully before you continue to use the Site. By using the Site, you agree to be bound by the Terms. You shall also be subject to any additional terms posted with respect to individual sections of the Site. Please review our Privacy Policy, which also governs your use of the Site, to understand our practices. If you do not agree, please discontinue using the Site. National Geographic reserves the right to change the Terms at any time without prior notice. Your continued access or use of the Site after such changes indicates your acceptance of the Terms as modified. It is your responsibility to review the Terms regularly. The Terms were last updated on 18 July 2011.";
String F = WordUtils.wrap(S, 20);
String[] F1 = F.split(System.lineSeparator());
System.out.println(Arrays.toString(F1));
}}
Output
[THESE TERMS AND, CONDITIONS OF, SERVICE (the Terms), ARE A LEGAL AND, BINDING AGREEMENT, BETWEEN YOU AND, NATIONAL GEOGRAPHIC, governing your use, of this site,, www.nationalgeographic.com,, which includes but, is not limited to, products, software, and services offered, by way of the, website such as the, Video Player,, Uploader, and other, applications that, link to these Terms, (the Site). Please, review the Terms, fully before you, continue to use the, Site. By using the, Site, you agree to, be bound by the, Terms. You shall, also be subject to, any additional terms, posted with respect, to individual, sections of the, Site. Please review, our Privacy Policy,, which also governs, your use of the, Site, to understand, our practices. If, you do not agree,, please discontinue, using the Site., National Geographic, reserves the right, to change the Terms, at any time without, prior notice. Your, continued access or, use of the Site, after such changes, indicates your, acceptance of the, Terms as modified., It is your, responsibility to, review the Terms, regularly. The Terms, were last updated on, 18 July 2011.]
Since Java 8 you can also use Streams to tackle such problems.
Following you can find a full example that utilizes Reduction using the .collect() method
I think this one should be shorter than other non-3rd-party solutions.
private static String multiLine(String longString, String splitter, int maxLength) {
return Arrays.stream(longString.split(splitter))
.collect(
ArrayList<String>::new,
(l, s) -> {
Function<ArrayList<String>, Integer> id = list -> list.size() - 1;
if(l.size() == 0 || (l.get(id.apply(l)).length() != 0 && l.get(id.apply(l)).length() + s.length() >= maxLength)) l.add("");
l.set(id.apply(l), l.get(id.apply(l)) + (l.get(id.apply(l)).length() == 0 ? "" : splitter) + s);
},
(l1, l2) -> l1.addAll(l2))
.stream().reduce((s1, s2) -> s1 + "\n" + s2).get();
}
public static void main(String[] args) {
String longString = "THESE TERMS AND CONDITIONS OF SERVICE (the Terms) ARE A LEGAL AND BINDING AGREEMENT BETWEEN YOU AND NATIONAL GEOGRAPHIC governing your use of this site, www.nationalgeographic.com, which includes but is not limited to products, software and services offered by way of the website such as the Video Player, Uploader, and other applications that link to these Terms (the Site). Please review the Terms fully before you continue to use the Site. By using the Site, you agree to be bound by the Terms. You shall also be subject to any additional terms posted with respect to individual sections of the Site. Please review our Privacy Policy, which also governs your use of the Site, to understand our practices. If you do not agree, please discontinue using the Site. National Geographic reserves the right to change the Terms at any time without prior notice. Your continued access or use of the Site after such changes indicates your acceptance of the Terms as modified. It is your responsibility to review the Terms regularly. The Terms were last updated on 18 July 2011.";
String SPLITTER = " ";
int MAX_LENGTH = 20;
System.out.println(multiLine(longString, SPLITTER, MAX_LENGTH));
}
Just iterate through the string word by word and break whenever a word passes the limit.
public String addLinebreaks(String input, int maxLineLength) {
StringTokenizer tok = new StringTokenizer(input, " ");
StringBuilder output = new StringBuilder(input.length());
int lineLen = 0;
while (tok.hasMoreTokens()) {
String word = tok.nextToken();
if (lineLen + word.length() > maxLineLength) {
output.append("\n");
lineLen = 0;
}
output.append(word);
lineLen += word.length();
}
return output.toString();
}
I just typed that in freehand, you may have to push and prod a bit to make it compile.
Bug: if a word in the input is longer than maxLineLength
it will be appended to the current line instead of on a too-long line of its own. I assume your line length is something like 80 or 120 characters, in which case this is unlikely to be a problem.
Thanks Barend Garvelink for your answer. I have modified the above code to fix the Bug: "if a word in the input is longer than maxCharInLine"
public String[] splitIntoLine(String input, int maxCharInLine){
StringTokenizer tok = new StringTokenizer(input, " ");
StringBuilder output = new StringBuilder(input.length());
int lineLen = 0;
while (tok.hasMoreTokens()) {
String word = tok.nextToken();
while(word.length() > maxCharInLine){
output.append(word.substring(0, maxCharInLine-lineLen) + "\n");
word = word.substring(maxCharInLine-lineLen);
lineLen = 0;
}
if (lineLen + word.length() > maxCharInLine) {
output.append("\n");
lineLen = 0;
}
output.append(word + " ");
lineLen += word.length() + 1;
}
// output.split();
// return output.toString();
return output.toString().split("\n");
}