View Javadoc

1   package org.apache.fulcrum.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.NoSuchElementException;
23  import java.util.StringTokenizer;
24  
25  import org.apache.commons.lang.StringUtils;
26  /**
27   * <code>WordWrapUtils</code> is a utility class to assist with word wrapping.
28   *
29   * @author Henri Yandell
30   * @author Stephen Colebourne
31   * @version $Id: WordWrapUtils.java 535465 2007-05-05 06:58:06Z tv $
32   */
33  public class WordWrapUtils {
34  
35      // Wrapping
36      //--------------------------------------------------------------------------
37  
38      /**
39       * Wraps a block of text to a specified line length.
40       * <p>
41       * This method takes a block of text, which might have long lines in it
42       * and wraps the long lines based on the supplied wrapColumn parameter.
43       * It was initially implemented for use by VelocityEmail. If there are tabs
44       * in inString, you are going to get results that are a bit strange,
45       * since tabs are a single character but are displayed as 4 or 8
46       * spaces. Remove the tabs.
47       *
48       * @param str  text which is in need of word-wrapping
49       * @param newline  the characters that define a newline
50       * @param wrapColumn  the column to wrap the words at
51       * @return the text with all the long lines word-wrapped
52       */
53      public static String wrapText(String str, String newline, int wrapColumn) {
54          StringTokenizer lineTokenizer = new StringTokenizer(str, newline, true);
55          StringBuffer stringBuffer = new StringBuffer();
56  
57          while (lineTokenizer.hasMoreTokens()) {
58              try {
59                  String nextLine = lineTokenizer.nextToken();
60  
61                  if (nextLine.length() > wrapColumn) {
62                      // This line is long enough to be wrapped.
63                      nextLine = wrapLine(nextLine, newline, wrapColumn);
64                  }
65  
66                  stringBuffer.append(nextLine);
67  
68              } catch (NoSuchElementException nsee) {
69                  // thrown by nextToken(), but I don't know why it would
70                  break;
71              }
72          }
73  
74          return (stringBuffer.toString());
75      }
76  
77      /**
78       * Wraps a single line of text.
79       * Called by wrapText() to do the real work of wrapping.
80       *
81       * @param line  a line which is in need of word-wrapping
82       * @param newline  the characters that define a newline
83       * @param wrapColumn  the column to wrap the words at
84       * @return a line with newlines inserted
85       */
86      private static String wrapLine(String line, String newline, int wrapColumn) {
87          StringBuffer wrappedLine = new StringBuffer();
88  
89          while (line.length() > wrapColumn) {
90              int spaceToWrapAt = line.lastIndexOf(' ', wrapColumn);
91  
92              if (spaceToWrapAt >= 0) {
93                  wrappedLine.append(line.substring(0, spaceToWrapAt));
94                  wrappedLine.append(newline);
95                  line = line.substring(spaceToWrapAt + 1);
96              }
97  
98              // This must be a really long word or URL. Pass it
99              // through unchanged even though it's longer than the
100             // wrapColumn would allow. This behavior could be
101             // dependent on a parameter for those situations when
102             // someone wants long words broken at line length.
103             else {
104                 spaceToWrapAt = line.indexOf(' ', wrapColumn);
105 
106                 if (spaceToWrapAt >= 0) {
107                     wrappedLine.append(line.substring(0, spaceToWrapAt));
108                     wrappedLine.append(newline);
109                     line = line.substring(spaceToWrapAt + 1);
110                 } else {
111                     wrappedLine.append(line);
112                     line = "";
113                 }
114             }
115         }
116 
117         // Whatever is left in line is short enough to just pass through
118         wrappedLine.append(line);
119 
120         return (wrappedLine.toString());
121     }
122 
123     // Word wrapping
124     //--------------------------------------------------------------------------
125 
126     /**
127      * Create a word-wrapped version of a String. Wrap at 80 characters and
128      * use newlines as the delimiter. If a word is over 80 characters long
129      * use a - sign to split it.
130      */
131     public static String wordWrap(String str) {
132         return wordWrap(str, 80, "\n", "-");
133     }
134     /**
135      * Create a word-wrapped version of a String. Wrap at a specified width and
136      * use newlines as the delimiter. If a word is over the width in lenght
137      * use a - sign to split it.
138      */
139     public static String wordWrap(String str, int width) {
140         return wordWrap(str, width, "\n", "-");
141     }
142     /**
143      * Word-wrap a string.
144      *
145      * @param str   String to word-wrap
146      * @param width int to wrap at
147      * @param delim String to use to separate lines
148      * @param split String to use to split a word greater than width long
149      *
150      * @return String that has been word wrapped
151      */
152     public static String wordWrap(String str, int width, String delim, String split) {
153         int sz = str.length();
154 
155         /// shift width up one. mainly as it makes the logic easier
156         width++;
157 
158         // our best guess as to an initial size
159         StringBuffer buffer = new StringBuffer(sz / width * delim.length() + sz);
160 
161         // every line will include a delim on the end
162         width = width - delim.length();
163 
164         int idx = -1;
165         String substr = null;
166 
167         // beware: i is rolled-back inside the loop
168         for (int i = 0; i < sz; i += width) {
169 
170             // on the last line
171             if (i > sz - width) {
172                 buffer.append(str.substring(i));
173                 break;
174             }
175 
176             // the current line
177             substr = str.substring(i, i + width);
178 
179             // is the delim already on the line
180             idx = substr.indexOf(delim);
181             if (idx != -1) {
182                 buffer.append(substr.substring(0, idx));
183                 buffer.append(delim);
184                 i -= width - idx - delim.length();
185 
186                 // Erase a space after a delim. Is this too obscure?
187                 if (substr.charAt(idx + 1) != '\n') {
188                     if (Character.isWhitespace(substr.charAt(idx + 1))) {
189                         i++;
190                     }
191                 }
192                 continue;
193             }
194 
195             idx = -1;
196 
197             // figure out where the last space is
198             char[] chrs = substr.toCharArray();
199             for (int j = width; j > 0; j--) {
200                 if (Character.isWhitespace(chrs[j - 1])) {
201                     idx = j;
202                     break;
203                 }
204             }
205 
206             // idx is the last whitespace on the line.
207             if (idx == -1) {
208                 for (int j = width; j > 0; j--) {
209                     if (chrs[j - 1] == '-') {
210                         idx = j;
211                         break;
212                     }
213                 }
214                 if (idx == -1) {
215                     buffer.append(substr);
216                     buffer.append(delim);
217                 } else {
218                     if (idx != width) {
219                         idx++;
220                     }
221                     buffer.append(substr.substring(0, idx));
222                     buffer.append(delim);
223                     i -= width - idx;
224                 }
225             } else {
226                 // insert spaces
227                 buffer.append(substr.substring(0, idx));
228                 buffer.append(StringUtils.repeat(" ", width - idx));
229                 buffer.append(delim);
230                 i -= width - idx;
231             }
232         }
233         return buffer.toString();
234     }
235 
236 }