*
* @return the list of justified lines
*/
- static List<String> left2(final String data, final int width) {
- List<String> result = new LinkedList<String>();
+ static List<String> left(final String data, final int width) {
+ List<String> lines = new LinkedList<String>();
- return result;
- }
+ for (String dataLine : data.split("\n")) {
+ String line = rightTrim(dataLine.replace("\t", " "));
- /**
- * Left-justify a string into a list of lines.
- *
- * @param str
- * the string
- * @param n
- * the maximum number of characters in a line
- * @return the list of lines
- */
- static List<String> left(final String str, final int n) {
- List<String> result = new LinkedList<String>();
+ if (width > 0 && line.length() > width) {
+ while (line.length() > 0) {
+ int i = Math.min(line.length(), width - 1); // -1 for "-"
- /*
- * General procedure:
- *
- * 1. Split on '\n' into paragraphs.
- *
- * 2. Scan each line, noting the position of the last
- * beginning-of-a-word.
- *
- * 3. Chop at the last #2 if the next beginning-of-a-word exceeds n.
- *
- * 4. Return the lines.
- */
+ boolean needDash = true;
+ // find the best space if any and if needed
+ int prevSpace = 0;
+ if (i < line.length()) {
+ prevSpace = -1;
+ int space = line.indexOf(' ');
- String[] rawLines = str.split("\n");
- for (int i = 0; i < rawLines.length; i++) {
- StringBuilder line = new StringBuilder();
- StringBuilder word = new StringBuilder();
- boolean inWord = false;
- for (int j = 0; j < rawLines[i].length(); j++) {
- char ch = rawLines[i].charAt(j);
- if ((ch == ' ') || (ch == '\t')) {
- if (inWord == true) {
- // We have just transitioned from a word to
- // whitespace. See if we have enough space to add
- // the word to the line.
- if (word.length() + line.length() > n) {
- // This word will exceed the line length. Wrap
- // at it instead.
- result.add(line.toString());
- line = new StringBuilder();
+ while (space > -1 && space <= i) {
+ prevSpace = space;
+ space = line.indexOf(' ', space + 1);
}
- if ((word.toString().startsWith(" "))
- && (line.length() == 0)) {
- line.append(word.substring(1));
- } else {
- line.append(word);
+
+ if (prevSpace > 0) {
+ i = prevSpace;
+ needDash = false;
+ }
+ }
+ //
+
+ // no dash before space/dash
+ if ((i + 1) < line.length()) {
+ char car = line.charAt(i);
+ char nextCar = line.charAt(i + 1);
+ if (nextCar == ' ' || car == '-' || nextCar == '-') {
+ needDash = false;
}
- word = new StringBuilder();
- word.append(ch);
- inWord = false;
- } else {
- // We are in the whitespace before another word. Do
- // nothing.
}
- } else {
- if (inWord == true) {
- // We are appending to a word.
- word.append(ch);
+
+ // if the space freed by the removed dash allows it, or if
+ // it is the last char, add the next char
+ if (!needDash || i >= line.length() - 1) {
+ int checkI = Math.min(i + 1, line.length());
+ if (checkI == i || checkI <= width) {
+ needDash = false;
+ i = checkI;
+ }
+ }
+
+ // no dash before parenthesis (but cannot add one more
+ // after)
+ if ((i + 1) < line.length()) {
+ char car = line.charAt(i + 1);
+ if (car == '(' || car == ')') {
+ needDash = false;
+ }
+ }
+
+ if (needDash) {
+ lines.add(rightTrim(line.substring(0, i)) + "-");
} else {
- // We have transitioned from whitespace to a word.
- word.append(ch);
- inWord = true;
+ lines.add(rightTrim(line.substring(0, i)));
}
- }
- } // next j
- if (word.length() + line.length() > n) {
- // This word will exceed the line length. Wrap at it
- // instead.
- result.add(line.toString());
- line = new StringBuilder();
- }
- if ((word.toString().startsWith(" ")) && (line.length() == 0)) {
- line.append(word.substring(1));
+ // full trim (remove spaces when cutting)
+ line = line.substring(i).trim();
+ }
} else {
- line.append(word);
+ lines.add(line);
}
- result.add(line.toString());
- } // next i
+ }
- return result;
+ return lines;
}
/**
return result;
}
+
+ /**
+ * Trim the given {@link String} on the right only.
+ *
+ * @param data
+ * the source {@link String}
+ * @return the right-trimmed String or Empty if it was NULL
+ */
+ static private String rightTrim(String data) {
+ if (data == null)
+ return "";
+
+ return ("|" + data).trim().substring(1);
+ }
}
package be.nikiroo.utils.test;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
addTest(new TestCase("Justifying") {
@Override
public void test() throws Exception {
- for (String data : new String[] { "test",
- "let's test some words", "" }) {
- int total = 0;
- for (String word : data.split((" "))) {
- total += word.replace("-", "").replace(" ", "")
- .length();
- }
- List<String> result = StringUtils.justifyText(data, 5,
- StringUtils.Alignment.LEFT);
-
- System.out.println("["+data+"] -> [");
-
- int totalResult = 0;
- for (String resultLine : result) {
- System.out.println(resultLine);
- for (String word : resultLine.split((" "))) {
- totalResult += word.replace("-", "")
- .replace(" ", "").length();
+ Map<String, Map<Integer, Entry<Alignment, List<String>>>> source = new HashMap<String, Map<Integer, Entry<Alignment, List<String>>>>();
+ addValue(source, Alignment.LEFT, "testy", 5, "testy");
+ addValue(source, Alignment.LEFT, "testy", 3, "te-", "sty");
+ addValue(source, Alignment.LEFT,
+ "Un petit texte qui se mettra sur plusieurs lignes",
+ 10, "Un petit", "texte qui", "se mettra", "sur",
+ "plusieurs", "lignes");
+ addValue(source, Alignment.LEFT,
+ "Un petit texte qui se mettra sur plusieurs lignes", 7,
+ "Un", "petit", "texte", "qui se", "mettra", "sur",
+ "plusie-", "urs", "lignes");
+ addValue(source, Alignment.RIGHT,
+ "Un petit texte qui se mettra sur plusieurs lignes", 7,
+ " Un", " petit", " texte", " qui se", " mettra",
+ " sur", "plusie-", " urs", " lignes");
+ addValue(source, Alignment.CENTER,
+ "Un petit texte qui se mettra sur plusieurs lignes", 7,
+ " Un ", " petit ", " texte ", "qui se ", "mettra ",
+ " sur ", "plusie-", " urs ", "lignes ");
+ addValue(source, Alignment.JUSTIFY,
+ "Un petit texte qui se mettra sur plusieurs lignes", 7,
+ "Un", "petit", "texte", "qui se", "mettra", "sur",
+ "plusie-", "urs", "lignes");
+ addValue(source, Alignment.JUSTIFY,
+ "Un petit texte qui se mettra sur plusieurs lignes",
+ 14, "Un petit", "texte qui se",
+ "mettra sur", "plusieurs lig-", "nes");
+
+ System.out.println();
+ for (String data : source.keySet()) {
+ for (int size : source.get(data).keySet()) {
+ Alignment align = source.get(data).get(size).getKey();
+ List<String> values = source.get(data).get(size)
+ .getValue();
+
+ List<String> result = StringUtils.justifyText(data,
+ size, align);
+
+ System.out.println("[" + data + " (" + size + ")"
+ + "] -> [");
+ for (int i = 0; i < result.size(); i++) {
+ String resultLine = result.get(i);
+ System.out.println(i + ": " + resultLine);
}
- }
- System.out.println("]");
+ System.out.println("]");
- assertEquals(
- "The number of letters ('-' not included) should be identical before and after",
- total, totalResult);
+ for (int i = 0; i < result.size() && i < values.size(); i++) {
+ assertEquals("The line " + i + " is not correct",
+ values.get(i), result.get(i));
+ }
+ }
}
+ System.out.println();
}
});
}
});
}
+
+ static private void addValue(
+ Map<String, Map<Integer, Entry<Alignment, List<String>>>> source,
+ final Alignment align, String input, int size,
+ final String... result) {
+ if (!source.containsKey(input)) {
+ source.put(input,
+ new HashMap<Integer, Entry<Alignment, List<String>>>());
+ }
+
+ source.get(input).put(size, new Entry<Alignment, List<String>>() {
+ @Override
+ public Alignment getKey() {
+ return align;
+ }
+
+ @Override
+ public List<String> getValue() {
+ return Arrays.asList(result);
+ }
+
+ @Override
+ public List<String> setValue(List<String> value) {
+ return null;
+ }
+ });
+ }
}