在我独立开发(而且很差劲)之前,我想知道是否存在一些现有的Java代码可以将文本行包装到给定的最大宽度。理想情况下它会:
- 保留原有的换行符
- 在单词边界上分割超过最大长度的行
- 通过插入连字符来分解长度超过最大行宽的单词
编辑: 这里没有 "像素",只有java.lang.String。 "最大宽度" 指的是一行上的字符数。
在我独立开发(而且很差劲)之前,我想知道是否存在一些现有的Java代码可以将文本行包装到给定的最大宽度。理想情况下它会:
编辑: 这里没有 "像素",只有java.lang.String。 "最大宽度" 指的是一行上的字符数。
Apache commons中包含WordUtils和wrap函数:
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/text/WordUtils.html
P.S.看起来这已经被弃用,你需要使用
代替。
使用word-wrap库(可以在Maven Central上获得)。
以下是使用它的一种方法:
String text = "hi there how are you going?";
String wrapped =
WordWrap.from(text)
.maxWidth(10)
.insertHyphens(true) // true is the default
.wrap();
输出结果为:
hi there
how are
you going?
该库保留行首空格,这是针对Apache commons-lang行为的一项抱怨。您还可以指定stringWidth
函数,以获得在呈现文本时精确到像素级的结果。
该库具有良好的单元测试覆盖率(考虑从网络上复制和粘贴代码块时要牢记这一点!)。
Maven 依赖项为:
<dependency>
<groupId>com.github.davidmoten</groupId>
<artifactId>word-wrap</artifactId>
<version>0.1.9</version>
</dependency>
private static final String LINEBREAK = "\n"; // or "\r\n";
public static String wrap(String string, int lineLength) {
StringBuilder b = new StringBuilder();
for (String line : string.split(Pattern.quote(LINEBREAK))) {
b.append(wrapLine(line, lineLength));
}
return b.toString();
}
private static String wrapLine(String line, int lineLength) {
if (line.length() == 0) return LINEBREAK;
if (line.length() <= lineLength) return line + LINEBREAK;
String[] words = line.split(" ");
StringBuilder allLines = new StringBuilder();
StringBuilder trimmedLine = new StringBuilder();
for (String word : words) {
if (trimmedLine.length() + 1 + word.length() <= lineLength) {
trimmedLine.append(word).append(" ");
} else {
allLines.append(trimmedLine).append(LINEBREAK);
trimmedLine = new StringBuilder();
trimmedLine.append(word).append(" ");
}
}
if (trimmedLine.length() > 0) {
allLines.append(trimmedLine);
}
allLines.append(linebreak);
return allLines.toString();
}
此解决方案将两个空格转换为一个空格(因此与Apache commons WordUtils存在相同的错误,即@jett提出的问题)。
return
之前要加上最后的 allLines.append(linebreak);
?似乎会在不需要的地方添加额外的换行符。 - JeffThompson/**Wraps a source String into a series of lines having a maximum specified length. The source is
* wrapped at: spaces, horizontal tabs, system newLine characters, or a specified newLine character
* sequence. Existing newLine character sequences in the source string, whether they be the system
* newLine or the specified newLine, are honored. Existing whitespace (spaces and horizontal tabs)
* is preserved.
* <p>
* When <tt>wrapLongWords</tt> is true, words having a length greater than the specified
* <tt>lineLength</tt> will be broken, the specified <tt>longWordBreak</tt> terminator appended,
* and a new line initiated with the text of the specified <tt>longWordLinePrefix</tt> string. The
* position of the break will be unceremoniously chosen such that <tt>ineLength</tt> is honored.
* One use of <tt>longWordLinePrefix</tt> is to effect "hanging indents" by specifying a series of
* spaces for this parameter. This parameter can contain the lineFeed character(s). Although
* <tt>longWordLinePrefix</tt> can contain the horizontal tab character, the results are not
* guaranteed because no attempt is made to determine the quantity of character positions occupied by a
* horizontal tab.</p>
* <p>
* Example usage:
* <pre>
* wrap( " A very long word is Abracadabra in my book", 11, "\n", true, "-", " ");</pre>
* returns (note the effect of the single-character lineFeed):
* <pre>
* A very
* long word
* is Abraca-
* dabra in
* my book</pre>
* Whereas, the following:
* <pre>
* wrap( " A very long word is Abracadabra in my book", 11, null, true, null, " ");</pre>
* returns (due to the 2-character system linefeed):
* <pre>
* A very
* long
* word is A
* bracada
* bra in
* my book</pre></p>
*
* @param src the String to be word wrapped, may be null
* @param lineLength the maximum line length, including the length of <tt>newLineStr</tt> and, when
* applicable, <tt>longWordLinePrefix</tt>. If the value is insufficient to accommodate
* these two parameters + 1 character, it will be increased accordingly.
* @param newLineStr the string to insert for a new line, or <code>null</code> to use the value
* reported as the system line separator by the JVM
* @param wrapLongWords when <tt>false</tt>, words longer than <tt>wrapLength</t> will not be broken
* @param longWordBreak string with which to precede <tt>newLineStr</tt> on each line of a broken word,
* excepting the last line, or <tt>null</tt> if this feature is not to be used
* @param longWordLinePrefix string with which to prefix each line of a broken word, subsequent
* to the first line, or <tt>null</tt> if no prefix is to be used
* @return a line with newlines inserted, or <code>null</code> if <tt>src</tt> is null
*/
public static String wrap( String src, int lineLength, String newLineStr, boolean wrapLongWords,
String longWordBreak, String longWordLinePrefix ) {
// Trivial case
if ( src == null ) return null;
if ( newLineStr == null )
newLineStr = System.getProperty( "line.separator" );
if ( longWordBreak == null )
longWordBreak = "";
if ( longWordLinePrefix == null )
longWordLinePrefix = "";
// Adjust maximum line length to accommodate the newLine string
lineLength -= newLineStr.length();
if ( lineLength < 1 )
lineLength = 1;
// Guard for long word break or prefix that would create an infinite loop
if ( wrapLongWords && lineLength - longWordBreak.length() - longWordLinePrefix.length() < 1 )
lineLength += longWordBreak.length() + longWordLinePrefix.length();
int
remaining = lineLength,
breakLength = longWordBreak.length();
Matcher m = Pattern.compile( ".+?[ \\t]|.+?(?:" + newLineStr + ")|.+?$" ).matcher( src );
StringBuilder cache = new StringBuilder();
while ( m.find() ) {
String word = m.group();
// Breakup long word
while ( wrapLongWords && word.length() > lineLength ) {
cache
.append( word.substring( 0, remaining - breakLength ) )
.append( longWordBreak )
.append( newLineStr );
word = longWordLinePrefix + word.substring( remaining - breakLength );
remaining = lineLength;
} // if
// Linefeed if word exceeds remaining space
if ( word.length() > remaining ) {
cache
.append( newLineStr )
.append( word );
remaining = lineLength;
} // if
// Word fits in remaining space
else
cache.append( word );
remaining -= word.length();
} // while
return cache.toString();
} // wrap()
完整的Java包装代码: 它也可以打破长单词。
public class Test {
public static void main(String[] args) {
String string = "Comments, notes or other information about the packages will print here. Your comments go here.";
List<String> list = wrapLine(string, 12);
for (String str : list)
System.out.println(str);
}
/**
* Wrap your string.
* @param line - String line which need to be wrapped.
* @param wrapLength - Wrapping threshold. Must be greater than 1.
* @return
*/
private static List<String> wrapLine(String line, int wrapLength) {
List<String> resultList = new ArrayList<String>();
if (line == null || line.length() == 0) {
resultList.add("");
return resultList;
}
if (line.length() <= wrapLength) {
resultList.add(line);
return resultList;
}
String[] words = line.split(" ");
for (String word : words) {
if (resultList.size() == 0) {
addNewWord(resultList, word, wrapLength);
} else {
String lastLine = resultList.get(resultList.size() - 1);
if (lastLine.length() + word.length() < wrapLength) {
lastLine = lastLine + word + " ";
resultList.set(resultList.size() - 1, lastLine);
} else if (lastLine.length() + word.length() == wrapLength) {
lastLine = lastLine + word;
resultList.set(resultList.size() - 1, lastLine);
} else {
if (isThereMuchSpace(lastLine, wrapLength)) {
breakLongWord(resultList, word, wrapLength, lastLine.length());
} else {
addNewWord(resultList, word, wrapLength);
}
}
}
}
return resultList;
}
private static void addNewWord(List<String> resultList, String word, int wrapLength) {
if (word.length() < wrapLength) {
resultList.add(word + " ");
} else if (word.length() == wrapLength) {
resultList.add(word);
} else {
breakLongWord(resultList, word, wrapLength, 0);
}
}
private static void breakLongWord(List<String> resultList, String word, int wrapLength, int offset) {
String part = word.substring(0, (wrapLength - offset) - 1);
if (offset > 1) {
String lastLine = resultList.get(resultList.size() - 1);
lastLine = lastLine + part + "-";
resultList.set(resultList.size() - 1, lastLine);
} else {
resultList.add(part + "-");
}
String nextPart = word.substring((wrapLength - offset) - 1, word.length());
if (nextPart.length() > wrapLength)
breakLongWord(resultList, nextPart, wrapLength, 0);
else if (nextPart.length() == wrapLength)
resultList.add(nextPart);
else
resultList.add(nextPart + " ");
}
private static boolean isThereMuchSpace(String line, double lineLength) {
double expectedPercent = (lineLength * 65) / 100;
if (line.length() <= expectedPercent)
return true;
return false;
}
}
public static List<String> stringBreak(String string, int maxChar) {
List<String> subLines = new ArrayList<String>();
int length = string.length();
int start = 0;
int end = maxChar;
if (length > maxChar) {
int noOfLines = (length / maxChar) + 1;
int endOfStr[] = new int[noOfLines];
for (int f = 0; f < noOfLines - 1; f++) {
int end1 = maxChar;
endOfStr[f] = end;
if (string.charAt(end - 1) != ' ') {
if (string.charAt(end - 2) == ' ') {
subLines.add(string.substring(start, end - 1));
start = end - 1;
end = end - 1 + end1;
} else if (string.charAt(end - 2) != ' '
&& string.charAt(end) == ' ') {
subLines.add(string.substring(start, end));
start = end;
end = end + end1;
} else if (string.charAt(end - 2) != ' ') {
subLines.add(string.substring(start, end) + "-");
start = end;
end = end + end1;
} else if (string.charAt(end + 2) == ' ') {
System.out.println("m here ............");
int lastSpaceIndex = string.substring(start, end)
.lastIndexOf("");
subLines.add(string.substring(start, lastSpaceIndex));
start = lastSpaceIndex;
end = lastSpaceIndex + end1;
}
} else {
subLines.add(string.substring(start, end));
start = end;
end = end + end1;
}
}
subLines.add(string.substring(endOfStr[noOfLines - 2], length));
}
return subLines;
}