package de.skuzzle.polly.tools.iterators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
* <p>This class provides an iterator interface to wrap a String into multiple lines with
* desired max line length.</p>
*
* <p>You can iterate over the wrapped lines using Javas for...each feature:</p>
* <pre>
* String s = "Very long long long String to wrap into several lines, where no " +
* "line is longer than the amount of characters you specify in the " +
* "WrapIterator's constructor. In our sample we use 10 characters.";
*
* for (String wrappedLine : new WrapIterator(s, 10)) {
* System.out.println(wrappedLine);
* }
* </pre>
*
* @author Simon
*
*/
public class WrapIterator implements Iterator<String>, Iterable<String> {
public static void main(String[] args) {
String s = "Very long long long String to wrap into several lines, where no " +
"line is longer than the amount of characters you specify in the " +
"WrapIterator's constructor. In our sample we use 15 characters. " +
"NowWeNeedAWordWithMoreThan15Characters. AnotherVeryLongRotzWord";
/*for (String wrappedLine : WrapIterator.get(s, 25)) {
System.out.println(wrappedLine);
}*/
System.out.println(wrapIntoString(s, 25));
wrapIntoString(s, 25);
}
public static Iterable<String> get(String s, int lineLength) {
return new WrapIterator(s, lineLength);
}
public static String wrapIntoString(String s, int lineLength) {
StringBuilder b = new StringBuilder(s.length() + 50);
Iterator<String> it = new WrapIterator(s, lineLength);
while (it.hasNext()) {
b.append(it.next());
if (it.hasNext()) {
b.append("\n");
}
}
return b.toString();
}
public static String[] wrapIntoArray(String s, int lineLength) {
return wrapIntoList(s, lineLength).toArray(new String[0]);
}
public static List<String> wrapIntoList(String s, int lineLength) {
ArrayList<String> result = new ArrayList<String>();
for (String line : new WrapIterator(s, lineLength)) {
result.add(line);
}
return result;
}
private ArrayIterator<String> words;
private int length;
public WrapIterator(String string, int length) {
if (length < 1) {
throw new IllegalArgumentException("Linelength must be at least 1 char");
}
this.length = length;
this.words = ArrayIterator.get(string.split(" "));
}
@Override
public boolean hasNext() {
return this.words.hasNext();
}
@Override
public String next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
StringBuilder b = new StringBuilder(this.length);
while (this.words.hasNext()) {
String word = this.words.next();
int i = this.words.hasNext() ? 1 : 0;
if (b.length() + word.length() + i <= this.length) {
b.append(word);
if (this.words.hasNext()) {
// only append space when this is not the last word on this line
b.append(" ");
}
} else {
if (word.length() >= this.length) {
// This word is longer than the max length. So it's cut into two
// pieces: the first piece gets the length to fit on the current
// line, the second piece will start the next line.
int free = this.length - b.length();
String right = word.substring(free);
if (right.length() > 0) {
this.words.replace(word.substring(free));
this.words.previous();
}
b.append(word.substring(0, free));
} else {
// The current word does not fit on the current line. So iteration
// is moved one step back so the word will start the next line.
this.words.previous();
}
return b.toString();
}
}
return b.toString();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<String> iterator() {
return this;
}
}