KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > util > StringUtils


1 /**
2  * $RCSfile: StringUtils.java,v $
3  * $Revision: 1.9 $
4  * $Date: 2005/04/11 21:05:47 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.util;
13
14 import java.io.UnsupportedEncodingException JavaDoc;
15 import java.security.MessageDigest JavaDoc;
16 import java.security.NoSuchAlgorithmException JavaDoc;
17 import java.text.BreakIterator JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Date JavaDoc;
20 import java.util.Locale JavaDoc;
21 import java.util.Random JavaDoc;
22
23 /**
24  * Utility class to peform common String manipulation algorithms.
25  */

26 public class StringUtils {
27
28     // Constants used by escapeHTMLTags
29
private static final char[] QUOTE_ENCODE = """.toCharArray();
30     private static final char[] AMP_ENCODE = "&".toCharArray();
31     private static final char[] LT_ENCODE = "<".toCharArray();
32     private static final char[] GT_ENCODE = ">".toCharArray();
33
34     /**
35      * Replaces all instances of oldString with newString in string.
36      *
37      * @param string the String to search to perform replacements on
38      * @param oldString the String that should be replaced by newString
39      * @param newString the String that will replace all instances of oldString
40      * @return a String will all instances of oldString replaced by newString
41      */

42     public static final String JavaDoc replace(String JavaDoc string, String JavaDoc oldString, String JavaDoc newString) {
43         if (string == null) {
44             return null;
45         }
46         int i = 0;
47         // Make sure that oldString appears at least once before doing any processing.
48
if ((i = string.indexOf(oldString, i)) >= 0) {
49             // Use char []'s, as they are more efficient to deal with.
50
char[] string2 = string.toCharArray();
51             char[] newString2 = newString.toCharArray();
52             int oLength = oldString.length();
53             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(string2.length);
54             buf.append(string2, 0, i).append(newString2);
55             i += oLength;
56             int j = i;
57             // Replace all remaining instances of oldString with newString.
58
while ((i = string.indexOf(oldString, i)) > 0) {
59                 buf.append(string2, j, i - j).append(newString2);
60                 i += oLength;
61                 j = i;
62             }
63             buf.append(string2, j, string2.length - j);
64             return buf.toString();
65         }
66         return string;
67     }
68
69     /**
70      * Replaces all instances of oldString with newString in line with the
71      * added feature that matches of newString in oldString ignore case.
72      *
73      * @param line the String to search to perform replacements on
74      * @param oldString the String that should be replaced by newString
75      * @param newString the String that will replace all instances of oldString
76      * @return a String will all instances of oldString replaced by newString
77      */

78     public static final String JavaDoc replaceIgnoreCase(String JavaDoc line, String JavaDoc oldString,
79                                                  String JavaDoc newString) {
80         if (line == null) {
81             return null;
82         }
83         String JavaDoc lcLine = line.toLowerCase();
84         String JavaDoc lcOldString = oldString.toLowerCase();
85         int i = 0;
86         if ((i = lcLine.indexOf(lcOldString, i)) >= 0) {
87             char[] line2 = line.toCharArray();
88             char[] newString2 = newString.toCharArray();
89             int oLength = oldString.length();
90             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(line2.length);
91             buf.append(line2, 0, i).append(newString2);
92             i += oLength;
93             int j = i;
94             while ((i = lcLine.indexOf(lcOldString, i)) > 0) {
95                 buf.append(line2, j, i - j).append(newString2);
96                 i += oLength;
97                 j = i;
98             }
99             buf.append(line2, j, line2.length - j);
100             return buf.toString();
101         }
102         return line;
103     }
104
105     /**
106      * Replaces all instances of oldString with newString in line with the
107      * added feature that matches of newString in oldString ignore case.
108      * The count paramater is set to the number of replaces performed.
109      *
110      * @param line the String to search to perform replacements on
111      * @param oldString the String that should be replaced by newString
112      * @param newString the String that will replace all instances of oldString
113      * @param count a value that will be updated with the number of replaces
114      * performed.
115      * @return a String will all instances of oldString replaced by newString
116      */

117     public static final String JavaDoc replaceIgnoreCase(String JavaDoc line, String JavaDoc oldString,
118                                                  String JavaDoc newString, int[] count) {
119         if (line == null) {
120             return null;
121         }
122         String JavaDoc lcLine = line.toLowerCase();
123         String JavaDoc lcOldString = oldString.toLowerCase();
124         int i = 0;
125         if ((i = lcLine.indexOf(lcOldString, i)) >= 0) {
126             int counter = 1;
127             char[] line2 = line.toCharArray();
128             char[] newString2 = newString.toCharArray();
129             int oLength = oldString.length();
130             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(line2.length);
131             buf.append(line2, 0, i).append(newString2);
132             i += oLength;
133             int j = i;
134             while ((i = lcLine.indexOf(lcOldString, i)) > 0) {
135                 counter++;
136                 buf.append(line2, j, i - j).append(newString2);
137                 i += oLength;
138                 j = i;
139             }
140             buf.append(line2, j, line2.length - j);
141             count[0] = counter;
142             return buf.toString();
143         }
144         return line;
145     }
146
147     /**
148      * Replaces all instances of oldString with newString in line.
149      * The count Integer is updated with number of replaces.
150      *
151      * @param line the String to search to perform replacements on
152      * @param oldString the String that should be replaced by newString
153      * @param newString the String that will replace all instances of oldString
154      * @return a String will all instances of oldString replaced by newString
155      */

156     public static final String JavaDoc replace(String JavaDoc line, String JavaDoc oldString,
157                                        String JavaDoc newString, int[] count) {
158         if (line == null) {
159             return null;
160         }
161         int i = 0;
162         if ((i = line.indexOf(oldString, i)) >= 0) {
163             int counter = 1;
164             char[] line2 = line.toCharArray();
165             char[] newString2 = newString.toCharArray();
166             int oLength = oldString.length();
167             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(line2.length);
168             buf.append(line2, 0, i).append(newString2);
169             i += oLength;
170             int j = i;
171             while ((i = line.indexOf(oldString, i)) > 0) {
172                 counter++;
173                 buf.append(line2, j, i - j).append(newString2);
174                 i += oLength;
175                 j = i;
176             }
177             buf.append(line2, j, line2.length - j);
178             count[0] = counter;
179             return buf.toString();
180         }
181         return line;
182     }
183
184     /**
185      * This method takes a string and strips out all tags except <br> tags while still leaving
186      * the tag body intact.
187      *
188      * @param in the text to be converted.
189      * @return the input string with all tags removed.
190      */

191     public static final String JavaDoc stripTags(String JavaDoc in) {
192         if (in == null) {
193             return null;
194         }
195         char ch;
196         int i = 0;
197         int last = 0;
198         char[] input = in.toCharArray();
199         int len = input.length;
200         StringBuilder JavaDoc out = new StringBuilder JavaDoc((int)(len * 1.3));
201         for (; i < len; i++) {
202             ch = input[i];
203             if (ch > '>') {
204                 continue;
205             }
206             else if (ch == '<') {
207                 if (i + 3 < len && input[i + 1] == 'b' && input[i + 2] == 'r' && input[i + 3] == '>') {
208                     i += 3;
209                     continue;
210                 }
211                 if (i > last) {
212                     out.append(input, last, i - last);
213                 }
214                 last = i + 1;
215             }
216             else if (ch == '>') {
217                 last = i + 1;
218             }
219         }
220         if (last == 0) {
221             return in;
222         }
223         if (i > last) {
224             out.append(input, last, i - last);
225         }
226         return out.toString();
227     }
228
229     /**
230      * This method takes a string which may contain HTML tags (ie, &lt;b&gt;,
231      * &lt;table&gt;, etc) and converts the '&lt'' and '&gt;' characters to
232      * their HTML escape sequences.
233      *
234      * @param in the text to be converted.
235      * @return the input string with the characters '&lt;' and '&gt;' replaced
236      * with their HTML escape sequences.
237      */

238     public static final String JavaDoc escapeHTMLTags(String JavaDoc in) {
239         if (in == null) {
240             return null;
241         }
242         char ch;
243         int i = 0;
244         int last = 0;
245         char[] input = in.toCharArray();
246         int len = input.length;
247         StringBuilder JavaDoc out = new StringBuilder JavaDoc((int)(len * 1.3));
248         for (; i < len; i++) {
249             ch = input[i];
250             if (ch > '>') {
251                 continue;
252             }
253             else if (ch == '<') {
254                 if (i > last) {
255                     out.append(input, last, i - last);
256                 }
257                 last = i + 1;
258                 out.append(LT_ENCODE);
259             }
260             else if (ch == '>') {
261                 if (i > last) {
262                     out.append(input, last, i - last);
263                 }
264                 last = i + 1;
265                 out.append(GT_ENCODE);
266             }
267         }
268         if (last == 0) {
269             return in;
270         }
271         if (i > last) {
272             out.append(input, last, i - last);
273         }
274         return out.toString();
275     }
276
277     /**
278      * Used by the hash method.
279      */

280     private static MessageDigest JavaDoc digest = null;
281
282     /**
283      * Hashes a String using the Md5 algorithm and returns the result as a
284      * String of hexadecimal numbers. This method is synchronized to avoid
285      * excessive MessageDigest object creation. If calling this method becomes
286      * a bottleneck in your code, you may wish to maintain a pool of
287      * MessageDigest objects instead of using this method.
288      * <p/>
289      * A hash is a one-way function -- that is, given an
290      * input, an output is easily computed. However, given the output, the
291      * input is almost impossible to compute. This is useful for passwords
292      * since we can store the hash and a hacker will then have a very hard time
293      * determining the original password.
294      * <p/>
295      * In Jive, every time a user logs in, we simply
296      * take their plain text password, compute the hash, and compare the
297      * generated hash to the stored hash. Since it is almost impossible that
298      * two passwords will generate the same hash, we know if the user gave us
299      * the correct password or not. The only negative to this system is that
300      * password recovery is basically impossible. Therefore, a reset password
301      * method is used instead.
302      *
303      * @param data the String to compute the hash of.
304      * @return a hashed version of the passed-in String
305      */

306     public synchronized static final String JavaDoc hash(String JavaDoc data) {
307         if (digest == null) {
308             try {
309                 digest = MessageDigest.getInstance("MD5");
310             }
311             catch (NoSuchAlgorithmException JavaDoc nsae) {
312                 Log.error("Failed to load the MD5 MessageDigest. " +
313                         "Jive will be unable to function normally.", nsae);
314             }
315         }
316         // Now, compute hash.
317
try {
318             digest.update(data.getBytes("utf-8"));
319         }
320         catch (UnsupportedEncodingException JavaDoc e) {
321             Log.error(e);
322         }
323         return encodeHex(digest.digest());
324     }
325
326     /**
327      * Turns an array of bytes into a String representing each byte as an
328      * unsigned hex number.
329      * <p/>
330      * Method by Santeri Paavolainen, Helsinki Finland 1996<br>
331      * (c) Santeri Paavolainen, Helsinki Finland 1996<br>
332      * Distributed under LGPL.
333      *
334      * @param bytes an array of bytes to convert to a hex-string
335      * @return generated hex string
336      */

337     public static final String JavaDoc encodeHex(byte[] bytes) {
338         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(bytes.length * 2);
339         int i;
340
341         for (i = 0; i < bytes.length; i++) {
342             if (((int)bytes[i] & 0xff) < 0x10) {
343                 buf.append("0");
344             }
345             buf.append(Long.toString((int)bytes[i] & 0xff, 16));
346         }
347         return buf.toString();
348     }
349
350     /**
351      * Turns a hex encoded string into a byte array. It is specifically meant
352      * to "reverse" the toHex(byte[]) method.
353      *
354      * @param hex a hex encoded String to transform into a byte array.
355      * @return a byte array representing the hex String[
356      */

357     public static final byte[] decodeHex(String JavaDoc hex) {
358         char[] chars = hex.toCharArray();
359         byte[] bytes = new byte[chars.length / 2];
360         int byteCount = 0;
361         for (int i = 0; i < chars.length; i += 2) {
362             int newByte = 0x00;
363             newByte |= hexCharToByte(chars[i]);
364             newByte <<= 4;
365             newByte |= hexCharToByte(chars[i + 1]);
366             bytes[byteCount] = (byte)newByte;
367             byteCount++;
368         }
369         return bytes;
370     }
371
372     /**
373      * Returns the the byte value of a hexadecmical char (0-f). It's assumed
374      * that the hexidecimal chars are lower case as appropriate.
375      *
376      * @param ch a hexedicmal character (0-f)
377      * @return the byte value of the character (0x00-0x0F)
378      */

379     private static final byte hexCharToByte(char ch) {
380         switch (ch) {
381             case '0':
382                 return 0x00;
383             case '1':
384                 return 0x01;
385             case '2':
386                 return 0x02;
387             case '3':
388                 return 0x03;
389             case '4':
390                 return 0x04;
391             case '5':
392                 return 0x05;
393             case '6':
394                 return 0x06;
395             case '7':
396                 return 0x07;
397             case '8':
398                 return 0x08;
399             case '9':
400                 return 0x09;
401             case 'a':
402                 return 0x0A;
403             case 'b':
404                 return 0x0B;
405             case 'c':
406                 return 0x0C;
407             case 'd':
408                 return 0x0D;
409             case 'e':
410                 return 0x0E;
411             case 'f':
412                 return 0x0F;
413         }
414         return 0x00;
415     }
416
417     //*********************************************************************
418
//* Base64 - a simple base64 encoder and decoder.
419
//*
420
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
421
//*
422
//* This code may be freely used for any purpose, either personal
423
//* or commercial, provided the authors copyright notice remains
424
//* intact.
425
//*********************************************************************
426

427     /**
428      * Encodes a String as a base64 String.
429      *
430      * @param data a String to encode.
431      * @return a base64 encoded String.
432      */

433     public static String JavaDoc encodeBase64(String JavaDoc data) {
434         byte[] bytes = null;
435         try {
436             bytes = data.getBytes("ISO-8859-1");
437         }
438         catch (UnsupportedEncodingException JavaDoc uee) {
439             Log.error(uee);
440         }
441         return encodeBase64(bytes);
442     }
443
444     /**
445      * Encodes a byte array into a base64 String.
446      *
447      * @param data a byte array to encode.
448      * @return a base64 encode String.
449      */

450     public static String JavaDoc encodeBase64(byte[] data) {
451         int c;
452         int len = data.length;
453         StringBuilder JavaDoc ret = new StringBuilder JavaDoc(((len / 3) + 1) * 4);
454         for (int i = 0; i < len; ++i) {
455             c = (data[i] >> 2) & 0x3f;
456             ret.append(cvt.charAt(c));
457             c = (data[i] << 4) & 0x3f;
458             if (++i < len)
459                 c |= (data[i] >> 4) & 0x0f;
460
461             ret.append(cvt.charAt(c));
462             if (i < len) {
463                 c = (data[i] << 2) & 0x3f;
464                 if (++i < len)
465                     c |= (data[i] >> 6) & 0x03;
466
467                 ret.append(cvt.charAt(c));
468             }
469             else {
470                 ++i;
471                 ret.append((char)fillchar);
472             }
473
474             if (i < len) {
475                 c = data[i] & 0x3f;
476                 ret.append(cvt.charAt(c));
477             }
478             else {
479                 ret.append((char)fillchar);
480             }
481         }
482         return ret.toString();
483     }
484
485     /**
486      * Decodes a base64 String.
487      *
488      * @param data a base64 encoded String to decode.
489      * @return the decoded String.
490      */

491     public static String JavaDoc decodeBase64(String JavaDoc data) {
492         byte[] bytes = null;
493         try {
494             bytes = data.getBytes("ISO-8859-1");
495         }
496         catch (UnsupportedEncodingException JavaDoc uee) {
497             Log.error(uee);
498         }
499         return decodeBase64(bytes);
500     }
501
502     /**
503      * Decodes a base64 aray of bytes.
504      *
505      * @param data a base64 encode byte array to decode.
506      * @return the decoded String.
507      */

508     public static String JavaDoc decodeBase64(byte[] data) {
509         int c, c1;
510         int len = data.length;
511         StringBuilder JavaDoc ret = new StringBuilder JavaDoc((len * 3) / 4);
512         for (int i = 0; i < len; ++i) {
513             c = cvt.indexOf(data[i]);
514             ++i;
515             c1 = cvt.indexOf(data[i]);
516             c = ((c << 2) | ((c1 >> 4) & 0x3));
517             ret.append((char)c);
518             if (++i < len) {
519                 c = data[i];
520                 if (fillchar == c)
521                     break;
522
523                 c = cvt.indexOf(c);
524                 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
525                 ret.append((char)c1);
526             }
527
528             if (++i < len) {
529                 c1 = data[i];
530                 if (fillchar == c1)
531                     break;
532
533                 c1 = cvt.indexOf(c1);
534                 c = ((c << 6) & 0xc0) | c1;
535                 ret.append((char)c);
536             }
537         }
538         return ret.toString();
539     }
540
541     private static final int fillchar = '=';
542     private static final String JavaDoc cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
543             + "abcdefghijklmnopqrstuvwxyz"
544             + "0123456789+/";
545
546     /**
547      * Converts a line of text into an array of lower case words using a
548      * BreakIterator.wordInstance(). <p>
549      * <p/>
550      * This method is under the Jive Open Source Software License and was
551      * written by Mark Imbriaco.
552      *
553      * @param text a String of text to convert into an array of words
554      * @return text broken up into an array of words.
555      */

556     public static final String JavaDoc[] toLowerCaseWordArray(String JavaDoc text) {
557         if (text == null || text.length() == 0) {
558             return new String JavaDoc[0];
559         }
560
561         ArrayList JavaDoc wordList = new ArrayList JavaDoc();
562         BreakIterator JavaDoc boundary = BreakIterator.getWordInstance();
563         boundary.setText(text);
564         int start = 0;
565
566         for (int end = boundary.next(); end != BreakIterator.DONE;
567              start = end, end = boundary.next()) {
568             String JavaDoc tmp = text.substring(start, end).trim();
569             // Remove characters that are not needed.
570
tmp = replace(tmp, "+", "");
571             tmp = replace(tmp, "/", "");
572             tmp = replace(tmp, "\\", "");
573             tmp = replace(tmp, "#", "");
574             tmp = replace(tmp, "*", "");
575             tmp = replace(tmp, ")", "");
576             tmp = replace(tmp, "(", "");
577             tmp = replace(tmp, "&", "");
578             if (tmp.length() > 0) {
579                 wordList.add(tmp);
580             }
581         }
582         return (String JavaDoc[])wordList.toArray(new String JavaDoc[wordList.size()]);
583     }
584
585     /**
586      * Pseudo-random number generator object for use with randomString().
587      * The Random class is not considered to be cryptographically secure, so
588      * only use these random Strings for low to medium security applications.
589      */

590     private static Random JavaDoc randGen = new Random JavaDoc();
591
592     /**
593      * Array of numbers and letters of mixed case. Numbers appear in the list
594      * twice so that there is a more equal chance that a number will be picked.
595      * We can use the array to get a random number or letter by picking a random
596      * array index.
597      */

598     private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
599             "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
600
601     /**
602      * Returns a random String of numbers and letters (lower and upper case)
603      * of the specified length. The method uses the Random class that is
604      * built-in to Java which is suitable for low to medium grade security uses.
605      * This means that the output is only pseudo random, i.e., each number is
606      * mathematically generated so is not truly random.<p>
607      * <p/>
608      * The specified length must be at least one. If not, the method will return
609      * null.
610      *
611      * @param length the desired length of the random String to return.
612      * @return a random String of numbers and letters of the specified length.
613      */

614     public static final String JavaDoc randomString(int length) {
615         if (length < 1) {
616             return null;
617         }
618         // Create a char buffer to put random letters and numbers in.
619
char[] randBuffer = new char[length];
620         for (int i = 0; i < randBuffer.length; i++) {
621             randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
622         }
623         return new String JavaDoc(randBuffer);
624     }
625
626     /**
627      * Intelligently chops a String at a word boundary (whitespace) that occurs
628      * at the specified index in the argument or before. However, if there is a
629      * newline character before <code>length</code>, the String will be chopped
630      * there. If no newline or whitespace is found in <code>string</code> up to
631      * the index <code>length</code>, the String will chopped at <code>length</code>.
632      * <p/>
633      * For example, chopAtWord("This is a nice String", 10) will return
634      * "This is a" which is the first word boundary less than or equal to 10
635      * characters into the original String.
636      *
637      * @param string the String to chop.
638      * @param length the index in <code>string</code> to start looking for a
639      * whitespace boundary at.
640      * @return a substring of <code>string</code> whose length is less than or
641      * equal to <code>length</code>, and that is chopped at whitespace.
642      */

643     public static final String JavaDoc chopAtWord(String JavaDoc string, int length) {
644         if (string == null || string.length() == 0) {
645             return string;
646         }
647
648         char[] charArray = string.toCharArray();
649         int sLength = string.length();
650         if (length < sLength) {
651             sLength = length;
652         }
653
654         // First check if there is a newline character before length; if so,
655
// chop word there.
656
for (int i = 0; i < sLength - 1; i++) {
657             // Windows
658
if (charArray[i] == '\r' && charArray[i + 1] == '\n') {
659                 return string.substring(0, i + 1);
660             }
661             // Unix
662
else if (charArray[i] == '\n') {
663                 return string.substring(0, i);
664             }
665         }
666         // Also check boundary case of Unix newline
667
if (charArray[sLength - 1] == '\n') {
668             return string.substring(0, sLength - 1);
669         }
670
671         // Done checking for newline, now see if the total string is less than
672
// the specified chop point.
673
if (string.length() < length) {
674             return string;
675         }
676
677         // No newline, so chop at the first whitespace.
678
for (int i = length - 1; i > 0; i--) {
679             if (charArray[i] == ' ') {
680                 return string.substring(0, i).trim();
681             }
682         }
683
684         // Did not find word boundary so return original String chopped at
685
// specified length.
686
return string.substring(0, length);
687     }
688
689     /**
690      * Reformats a string where lines that are longer than <tt>width</tt>
691      * are split apart at the earliest wordbreak or at maxLength, whichever is
692      * sooner. If the width specified is less than 5 or greater than the input
693      * Strings length the string will be returned as is.
694      * <p/>
695      * Please note that this method can be lossy - trailing spaces on wrapped
696      * lines may be trimmed.
697      *
698      * @param input the String to reformat.
699      * @param width the maximum length of any one line.
700      * @return a new String with reformatted as needed.
701      */

702     public static String JavaDoc wordWrap(String JavaDoc input, int width, Locale JavaDoc locale) {
703         // protect ourselves
704
if (input == null) {
705             return "";
706         }
707         else if (width < 5) {
708             return input;
709         }
710         else if (width >= input.length()) {
711             return input;
712         }
713
714         // default locale
715
if (locale == null) {
716             locale = JiveGlobals.getLocale();
717         }
718
719         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(input);
720         boolean endOfLine = false;
721         int lineStart = 0;
722
723         for (int i = 0; i < buf.length(); i++) {
724             if (buf.charAt(i) == '\n') {
725                 lineStart = i + 1;
726                 endOfLine = true;
727             }
728
729             // handle splitting at width character
730
if (i > lineStart + width - 1) {
731                 if (!endOfLine) {
732                     int limit = i - lineStart - 1;
733                     BreakIterator JavaDoc breaks = BreakIterator.getLineInstance(locale);
734                     breaks.setText(buf.substring(lineStart, i));
735                     int end = breaks.last();
736
737                     // if the last character in the search string isn't a space,
738
// we can't split on it (looks bad). Search for a previous
739
// break character
740
if (end == limit + 1) {
741                         if (!Character.isWhitespace(buf.charAt(lineStart + end))) {
742                             end = breaks.preceding(end - 1);
743                         }
744                     }
745
746                     // if the last character is a space, replace it with a \n
747
if (end != BreakIterator.DONE && end == limit + 1) {
748                         buf.replace(lineStart + end, lineStart + end + 1, "\n");
749                         lineStart = lineStart + end;
750                     }
751                     // otherwise, just insert a \n
752
else if (end != BreakIterator.DONE && end != 0) {
753                         buf.insert(lineStart + end, '\n');
754                         lineStart = lineStart + end + 1;
755                     }
756                     else {
757                         buf.insert(i, '\n');
758                         lineStart = i + 1;
759                     }
760                 }
761                 else {
762                     buf.insert(i, '\n');
763                     lineStart = i + 1;
764                     endOfLine = false;
765                 }
766             }
767         }
768
769         return buf.toString();
770     }
771
772     /**
773      * Escapes all necessary characters in the String so that it can be used in SQL
774      *
775      * @param string the string to escape.
776      * @return the string with appropriate characters escaped.
777      */

778     public static final String JavaDoc escapeForSQL(String JavaDoc string) {
779         if (string == null) {
780             return null;
781         }
782         else if (string.length() == 0) {
783             return string;
784         }
785
786         char ch;
787         char[] input = string.toCharArray();
788         int i = 0;
789         int last = 0;
790         int len = input.length;
791         StringBuilder JavaDoc out = null;
792         for (; i < len; i++) {
793             ch = input[i];
794
795             if (ch == '\'') {
796                 if (out == null) {
797                      out = new StringBuilder JavaDoc(len + 2);
798                 }
799                 if (i > last) {
800                     out.append(input, last, i - last);
801                 }
802                 last = i + 1;
803                 out.append('\'').append('\'');
804             }
805         }
806
807         if (out == null) {
808             return string;
809         }
810         else if (i > last) {
811             out.append(input, last, i - last);
812         }
813
814         return out.toString();
815     }
816
817     /**
818      * Escapes all necessary characters in the String so that it can be used
819      * in an XML doc.
820      *
821      * @param string the string to escape.
822      * @return the string with appropriate characters escaped.
823      */

824     public static final String JavaDoc escapeForXML(String JavaDoc string) {
825         if (string == null) {
826             return null;
827         }
828         char ch;
829         int i = 0;
830         int last = 0;
831         char[] input = string.toCharArray();
832         int len = input.length;
833         StringBuilder JavaDoc out = new StringBuilder JavaDoc((int)(len * 1.3));
834         for (; i < len; i++) {
835             ch = input[i];
836             if (ch > '>') {
837                 continue;
838             }
839             else if (ch == '<') {
840                 if (i > last) {
841                     out.append(input, last, i - last);
842                 }
843                 last = i + 1;
844                 out.append(LT_ENCODE);
845             }
846             else if (ch == '&') {
847                 if (i > last) {
848                     out.append(input, last, i - last);
849                 }
850                 last = i + 1;
851                 out.append(AMP_ENCODE);
852             }
853             else if (ch == '"') {
854                 if (i > last) {
855                     out.append(input, last, i - last);
856                 }
857                 last = i + 1;
858                 out.append(QUOTE_ENCODE);
859             }
860         }
861         if (last == 0) {
862             return string;
863         }
864         if (i > last) {
865             out.append(input, last, i - last);
866         }
867         return out.toString();
868     }
869
870     /**
871      * Unescapes the String by converting XML escape sequences back into normal
872      * characters.
873      *
874      * @param string the string to unescape.
875      * @return the string with appropriate characters unescaped.
876      */

877     public static final String JavaDoc unescapeFromXML(String JavaDoc string) {
878         string = replace(string, "&lt;", "<");
879         string = replace(string, "&gt;", ">");
880         string = replace(string, "&quot;", "\"");
881         return replace(string, "&amp;", "&");
882     }
883
884     private static final char[] zeroArray =
885             "0000000000000000000000000000000000000000000000000000000000000000".toCharArray();
886
887     /**
888      * Pads the supplied String with 0's to the specified length and returns
889      * the result as a new String. For example, if the initial String is
890      * "9999" and the desired length is 8, the result would be "00009999".
891      * This type of padding is useful for creating numerical values that need
892      * to be stored and sorted as character data. Note: the current
893      * implementation of this method allows for a maximum <tt>length</tt> of
894      * 64.
895      *
896      * @param string the original String to pad.
897      * @param length the desired length of the new padded String.
898      * @return a new String padded with the required number of 0's.
899      */

900     public static final String JavaDoc zeroPadString(String JavaDoc string, int length) {
901         if (string == null || string.length() > length) {
902             return string;
903         }
904         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(length);
905         buf.append(zeroArray, 0, length - string.length()).append(string);
906         return buf.toString();
907     }
908
909     /**
910      * Formats a Date as a fifteen character long String made up of the Date's
911      * padded millisecond value.
912      *
913      * @return a Date encoded as a String.
914      */

915     public static final String JavaDoc dateToMillis(Date JavaDoc date) {
916         return zeroPadString(Long.toString(date.getTime()), 15);
917     }
918 }
Popular Tags