KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > template > utility > StringUtil


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.template.utility;
54
55 import java.io.UnsupportedEncodingException JavaDoc;
56 import java.util.*;
57 import freemarker.template.Template;
58 import freemarker.core.ParseException;
59 import freemarker.core.Environment;
60
61 /**
62  * Some text related utilities.
63  *
64  * @version $Id: StringUtil.java,v 1.48 2005/06/01 22:39:08 ddekany Exp $
65  */

66 public class StringUtil {
67     private static final char[] ESCAPES = createEscapes();
68
69     /*
70      * For better performance most methods are folded down. Don't you scream... :)
71      */

72
73     /**
74      * HTML encoding (does not convert line breaks).
75      * Replaces all '>' '<' '&' and '"' with entity reference
76      */

77     public static String JavaDoc HTMLEnc(String JavaDoc s) {
78         int ln = s.length();
79         for (int i = 0; i < ln; i++) {
80             char c = s.charAt(i);
81             if (c == '<' || c == '>' || c == '&' || c == '"') {
82                 StringBuffer JavaDoc b =
83                         new StringBuffer JavaDoc(s.substring(0, i));
84                 switch (c) {
85                     case '<': b.append("&lt;"); break;
86                     case '>': b.append("&gt;"); break;
87                     case '&': b.append("&amp;"); break;
88                     case '"': b.append("&quot;"); break;
89                 }
90                 i++;
91                 int next = i;
92                 while (i < ln) {
93                     c = s.charAt(i);
94                     if (c == '<' || c == '>' || c == '&' || c == '"') {
95                         b.append(s.substring(next, i));
96                         switch (c) {
97                             case '<': b.append("&lt;"); break;
98                             case '>': b.append("&gt;"); break;
99                             case '&': b.append("&amp;"); break;
100                             case '"': b.append("&quot;"); break;
101                         }
102                         next = i + 1;
103                     }
104                     i++;
105                 }
106                 if (next < ln) b.append(s.substring(next));
107                 s = b.toString();
108                 break;
109             } // if c ==
110
} // for
111
return s;
112     }
113
114     /**
115      * XML Encoding.
116      * Replaces all '&gt;' '&lt;' '&amp;', "'" and '"' with entity reference
117      */

118     public static String JavaDoc XMLEnc(String JavaDoc s) {
119         int ln = s.length();
120         for (int i = 0; i < ln; i++) {
121             char c = s.charAt(i);
122             if (c == '<' || c == '>' || c == '&' || c == '"' || c == '\'') {
123                 StringBuffer JavaDoc b =
124                         new StringBuffer JavaDoc(s.substring(0, i));
125                 switch (c) {
126                     case '<': b.append("&lt;"); break;
127                     case '>': b.append("&gt;"); break;
128                     case '&': b.append("&amp;"); break;
129                     case '"': b.append("&quot;"); break;
130                     case '\'': b.append("&apos;"); break;
131                 }
132                 i++;
133                 int next = i;
134                 while (i < ln) {
135                     c = s.charAt(i);
136                     if (c == '<' || c == '>' || c == '&' || c == '"' || c == '\'') {
137                         b.append(s.substring(next, i));
138                         switch (c) {
139                             case '<': b.append("&lt;"); break;
140                             case '>': b.append("&gt;"); break;
141                             case '&': b.append("&amp;"); break;
142                             case '"': b.append("&quot;"); break;
143                             case '\'': b.append("&apos;"); break;
144                         }
145                         next = i + 1;
146                     }
147                     i++;
148                 }
149                 if (next < ln) b.append(s.substring(next));
150                 s = b.toString();
151                 break;
152             } // if c ==
153
} // for
154
return s;
155     }
156
157     /**
158      * XML encoding without replacing apostrophes.
159      * @see #XMLEnc(String)
160      */

161     public static String JavaDoc XMLEncNA(String JavaDoc s) {
162         int ln = s.length();
163         for (int i = 0; i < ln; i++) {
164             char c = s.charAt(i);
165             if (c == '<' || c == '>' || c == '&' || c == '"') {
166                 StringBuffer JavaDoc b =
167                         new StringBuffer JavaDoc(s.substring(0, i));
168                 switch (c) {
169                     case '<': b.append("&lt;"); break;
170                     case '>': b.append("&gt;"); break;
171                     case '&': b.append("&amp;"); break;
172                     case '"': b.append("&quot;"); break;
173                 }
174                 i++;
175                 int next = i;
176                 while (i < ln) {
177                     c = s.charAt(i);
178                     if (c == '<' || c == '>' || c == '&' || c == '"') {
179                         b.append(s.substring(next, i));
180                         switch (c) {
181                             case '<': b.append("&lt;"); break;
182                             case '>': b.append("&gt;"); break;
183                             case '&': b.append("&amp;"); break;
184                             case '"': b.append("&quot;"); break;
185                         }
186                         next = i + 1;
187                     }
188                     i++;
189                 }
190                 if (next < ln) b.append(s.substring(next));
191                 s = b.toString();
192                 break;
193             } // if c ==
194
} // for
195
return s;
196     }
197
198     /**
199      * XML encoding for attributes valies quoted with <tt>"</tt> (not with <tt>'</tt>!).
200      * Also can be used for HTML attributes that are quoted with <tt>"</tt>.
201      * @see #XMLEnc(String)
202      */

203     public static String JavaDoc XMLEncQAttr(String JavaDoc s) {
204         int ln = s.length();
205         for (int i = 0; i < ln; i++) {
206             char c = s.charAt(i);
207             if (c == '<' || c == '&' || c == '"') {
208                 StringBuffer JavaDoc b =
209                         new StringBuffer JavaDoc(s.substring(0, i));
210                 switch (c) {
211                     case '<': b.append("&lt;"); break;
212                     case '&': b.append("&amp;"); break;
213                     case '"': b.append("&quot;"); break;
214                 }
215                 i++;
216                 int next = i;
217                 while (i < ln) {
218                     c = s.charAt(i);
219                     if (c == '<' || c == '&' || c == '"') {
220                         b.append(s.substring(next, i));
221                         switch (c) {
222                             case '<': b.append("&lt;"); break;
223                             case '&': b.append("&amp;"); break;
224                             case '"': b.append("&quot;"); break;
225                         }
226                         next = i + 1;
227                     }
228                     i++;
229                 }
230                 if (next < ln) {
231                     b.append(s.substring(next));
232                 }
233                 s = b.toString();
234                 break;
235             } // if c ==
236
} // for
237
return s;
238     }
239
240     /**
241      * XML encoding without replacing apostrophes and quotation marks and greater-than signs.
242      * @see #XMLEnc(String)
243      */

244     public static String JavaDoc XMLEncNQG(String JavaDoc s) {
245         int ln = s.length();
246         for (int i = 0; i < ln; i++) {
247             char c = s.charAt(i);
248             if (c == '<' || c == '&') {
249                 StringBuffer JavaDoc b =
250                         new StringBuffer JavaDoc(s.substring(0, i));
251                 switch (c) {
252                     case '<': b.append("&lt;"); break;
253                     case '&': b.append("&amp;"); break;
254                 }
255                 i++;
256                 int next = i;
257                 while (i < ln) {
258                     c = s.charAt(i);
259                     if (c == '<' || c == '&') {
260                         b.append(s.substring(next, i));
261                         switch (c) {
262                             case '<': b.append("&lt;"); break;
263                             case '&': b.append("&amp;"); break;
264                         }
265                         next = i + 1;
266                     }
267                     i++;
268                 }
269                 if (next < ln) b.append(s.substring(next));
270                 s = b.toString();
271                 break;
272             } // if c ==
273
} // for
274
return s;
275     }
276     
277     /**
278      * Rich Text Format encoding (does not replace line breaks).
279      * Escapes all '\' '{' '}' and '"'
280      */

281     public static String JavaDoc RTFEnc(String JavaDoc s) {
282         int ln = s.length();
283         for (int i = 0; i < ln; i++) {
284             char c = s.charAt(i);
285             if (c == '\\' || c == '{' || c == '}') {
286                 StringBuffer JavaDoc b =
287                         new StringBuffer JavaDoc(s.substring(0, i));
288                 switch (c) {
289                     case '\\': b.append("\\\\"); break;
290                     case '{': b.append("\\{"); break;
291                     case '}': b.append("\\}"); break;
292                 }
293                 i++;
294                 int next = i;
295                 while (i < ln) {
296                     c = s.charAt(i);
297                     if (c == '\\' || c == '{' || c == '}') {
298                         b.append(s.substring(next, i));
299                         switch (c) {
300                             case '\\': b.append("\\\\"); break;
301                             case '{': b.append("\\{"); break;
302                             case '}': b.append("\\}"); break;
303                         }
304                         next = i + 1;
305                     }
306                     i++;
307                 }
308                 if (next < ln) b.append(s.substring(next));
309                 s = b.toString();
310                 break;
311             } // if c ==
312
} // for
313
return s;
314     }
315
316     /**
317      * URL encoding (like%20this).
318      */

319     public static String JavaDoc URLEnc(String JavaDoc s, String JavaDoc charset)
320             throws UnsupportedEncodingException JavaDoc {
321         int ln = s.length();
322         int i;
323         for (i = 0; i < ln; i++) {
324             char c = s.charAt(i);
325             if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
326                     || c >= '0' && c <= '9'
327                     || c == '_' || c == '-' || c == '.' || c == '!' || c == '~'
328                     || c >= '\'' && c <= '*')) {
329                 break;
330             }
331         }
332         if (i == ln) {
333             // Nothing to escape
334
return s;
335         }
336
337         StringBuffer JavaDoc b = new StringBuffer JavaDoc(ln + ln / 3 + 2);
338         b.append(s.substring(0, i));
339
340         int encstart = i;
341         for (i++; i < ln; i++) {
342             char c = s.charAt(i);
343             if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
344                     || c >= '0' && c <= '9'
345                     || c == '_' || c == '-' || c == '.' || c == '!' || c == '~'
346                     || c >= '\'' && c <= '*') {
347                 if (encstart != -1) {
348                     byte[] o = s.substring(encstart, i).getBytes(charset);
349                     for (int j = 0; j < o.length; j++) {
350                         b.append('%');
351                         byte bc = o[j];
352                         int c1 = bc & 0x0F;
353                         int c2 = (bc >> 4) & 0x0F;
354                         b.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A'));
355                         b.append((char) (c1 < 10 ? c1 + '0' : c1 - 10 + 'A'));
356                     }
357                     encstart = -1;
358                 }
359                 b.append(c);
360             } else {
361                 if (encstart == -1) {
362                     encstart = i;
363                 }
364             }
365         }
366         if (encstart != -1) {
367             byte[] o = s.substring(encstart, i).getBytes(charset);
368             for (int j = 0; j < o.length; j++) {
369                 b.append('%');
370                 byte bc = o[j];
371                 int c1 = bc & 0x0F;
372                 int c2 = (bc >> 4) & 0x0F;
373                 b.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A'));
374                 b.append((char) (c1 < 10 ? c1 + '0' : c1 - 10 + 'A'));
375             }
376         }
377         
378         return b.toString();
379     }
380     
381     private static char[] createEscapes()
382     {
383         char[] escapes = new char['\\' + 1];
384         for(int i = 0; i < 32; ++i)
385         {
386             escapes[i] = 1;
387         }
388         escapes['\\'] = '\\';
389         escapes['\''] = '\'';
390         escapes['"'] = '"';
391         escapes['<'] = 'l';
392         escapes['>'] = 'g';
393         escapes['&'] = 'a';
394         escapes['\b'] = 'b';
395         escapes['\t'] = 't';
396         escapes['\n'] = 'n';
397         escapes['\f'] = 'f';
398         escapes['\r'] = 'r';
399         escapes['$'] = '$';
400         return escapes;
401     }
402
403     public static String JavaDoc FTLStringLiteralEnc(String JavaDoc s)
404     {
405         StringBuffer JavaDoc buf = null;
406         int l = s.length();
407         int el = ESCAPES.length;
408         for(int i = 0; i < l; i++)
409         {
410             char c = s.charAt(i);
411             if(c < el)
412             {
413                 char escape = ESCAPES[c];
414                 switch(escape)
415                 {
416                     case 0:
417                     {
418                         if (buf != null) {
419                             buf.append(c);
420                         }
421                         break;
422                     }
423                     case 1:
424                     {
425                         if (buf == null) {
426                             buf = new StringBuffer JavaDoc(s.length() + 3);
427                             buf.append(s.substring(0, i));
428                         }
429                         // hex encoding for characters below 0x20
430
// that have no other escape representation
431
buf.append("\\x00");
432                         int c2 = (c >> 4) & 0x0F;
433                         c = (char) (c & 0x0F);
434                         buf.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A'));
435                         buf.append((char) (c < 10 ? c + '0' : c - 10 + 'A'));
436                         break;
437                     }
438                     default:
439                     {
440                         if (buf == null) {
441                             buf = new StringBuffer JavaDoc(s.length() + 2);
442                             buf.append(s.substring(0, i));
443                         }
444                         buf.append('\\');
445                         buf.append(escape);
446                     }
447                 }
448             } else {
449                 if (buf != null) {
450                     buf.append(c);
451                 }
452             }
453         }
454         return buf == null ? s : buf.toString();
455     }
456
457     /**
458      * FTL string literal decoding.
459      *
460      * \\, \", \', \n, \t, \r, \b and \f will be replaced according to
461      * Java rules. In additional, it knows \g, \l, \a and \{ which are
462      * replaced with &lt;, >, &amp; and { respectively.
463      * \x works as hexadecimal character code escape. The character
464      * codes are interpreted according to UCS basic plane (Unicode).
465      * "f\x006Fo", "f\x06Fo" and "f\x6Fo" will be "foo".
466      * "f\x006F123" will be "foo123" as the maximum number of digits is 4.
467      *
468      * All other \X (where X is any character not mentioned above or End-of-string)
469      * will cause a ParseException.
470      *
471      * @param s String literal <em>without</em> the surrounding quotation marks
472      * @return String with all escape sequences resolved
473      * @throws ParseException if there string contains illegal escapes
474      */

475     public static String JavaDoc FTLStringLiteralDec(String JavaDoc s) throws ParseException {
476
477         int idx = s.indexOf('\\');
478         if (idx == -1) {
479             return s;
480         }
481
482         int lidx = s.length() - 1;
483         int bidx = 0;
484         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(lidx);
485         do {
486             buf.append(s.substring(bidx, idx));
487             if (idx >= lidx) {
488                 throw new ParseException("The last character of string literal is backslash", 0,0);
489             }
490             char c = s.charAt(idx + 1);
491             switch (c) {
492                 case '"':
493                     buf.append('"');
494                     bidx = idx + 2;
495                     break;
496                 case '\'':
497                     buf.append('\'');
498                     bidx = idx + 2;
499                     break;
500                 case '\\':
501                     buf.append('\\');
502                     bidx = idx + 2;
503                     break;
504                 case 'n':
505                     buf.append('\n');
506                     bidx = idx + 2;
507                     break;
508                 case 'r':
509                     buf.append('\r');
510                     bidx = idx + 2;
511                     break;
512                 case 't':
513                     buf.append('\t');
514                     bidx = idx + 2;
515                     break;
516                 case 'f':
517                     buf.append('\f');
518                     bidx = idx + 2;
519                     break;
520                 case 'b':
521                     buf.append('\b');
522                     bidx = idx + 2;
523                     break;
524                 case 'g':
525                     buf.append('>');
526                     bidx = idx + 2;
527                     break;
528                 case 'l':
529                     buf.append('<');
530                     bidx = idx + 2;
531                     break;
532                 case 'a':
533                     buf.append('&');
534                     bidx = idx + 2;
535                     break;
536                 case '{':
537                     buf.append('{');
538                     bidx = idx + 2;
539                     break;
540                 case 'x': {
541                     idx += 2;
542                     int x = idx;
543                     int y = 0;
544                     int z = lidx > idx + 3 ? idx + 3 : lidx;
545                     while (idx <= z) {
546                         char b = s.charAt(idx);
547                         if (b >= '0' && b <= '9') {
548                             y <<= 4;
549                             y += b - '0';
550                         } else if (b >= 'a' && b <= 'f') {
551                             y <<= 4;
552                             y += b - 'a' + 10;
553                         } else if (b >= 'A' && b <= 'F') {
554                             y <<= 4;
555                             y += b - 'A' + 10;
556                         } else {
557                             break;
558                         }
559                         idx++;
560                     }
561                     if (x < idx) {
562                         buf.append((char) y);
563                     } else {
564                         throw new ParseException("Invalid \\x escape in a string literal",0,0);
565                     }
566                     bidx = idx;
567                     break;
568                 }
569                 default:
570                     throw new ParseException("Invalid escape sequence (\\" + c + ") in a string literal",0,0);
571             }
572             idx = s.indexOf('\\', bidx);
573         } while (idx != -1);
574         buf.append(s.substring(bidx));
575
576         return buf.toString();
577     }
578
579     public static Locale deduceLocale(String JavaDoc input) {
580        Locale locale = Locale.getDefault();
581        if (input.charAt(0) == '"') input = input.substring(1, input.length() -1);
582        StringTokenizer st = new StringTokenizer(input, ",_ ");
583        String JavaDoc lang = "", country = "";
584        if (st.hasMoreTokens()) {
585           lang = st.nextToken();
586        }
587        if (st.hasMoreTokens()) {
588           country = st.nextToken();
589        }
590        if (!st.hasMoreTokens()) {
591           locale = new Locale(lang, country);
592        }
593        else {
594           locale = new Locale(lang, country, st.nextToken());
595        }
596        return locale;
597     }
598
599     public static String JavaDoc capitalize(String JavaDoc s) {
600         StringTokenizer st = new StringTokenizer(s, " \t\r\n", true);
601         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(s.length());
602         while (st.hasMoreTokens()) {
603             String JavaDoc tok = st.nextToken();
604             buf.append(tok.substring(0, 1).toUpperCase());
605             buf.append(tok.substring(1).toLowerCase());
606         }
607         return buf.toString();
608     }
609
610     public static boolean getYesNo(String JavaDoc s) {
611         if (s.startsWith("\"")) {
612             s = s.substring(1, s.length() -1);
613
614         }
615         if (s.equalsIgnoreCase("n")
616                 || s.equalsIgnoreCase("no")
617                 || s.equalsIgnoreCase("f")
618                 || s.equalsIgnoreCase("false")) {
619             return false;
620         }
621         else if (s.equalsIgnoreCase("y")
622                 || s.equalsIgnoreCase("yes")
623                 || s.equalsIgnoreCase("t")
624                 || s.equalsIgnoreCase("true")) {
625             return true;
626         }
627         throw new IllegalArgumentException JavaDoc("Illegal boolean value: " + s);
628     }
629
630     /**
631      * Splits a string at the specified character.
632      */

633     public static String JavaDoc[] split(String JavaDoc s, char c) {
634         int i, b, e;
635         int cnt;
636         String JavaDoc res[];
637         int ln = s.length();
638
639         i = 0;
640         cnt = 1;
641         while ((i = s.indexOf(c, i)) != -1) {
642             cnt++;
643             i++;
644         }
645         res = new String JavaDoc[cnt];
646
647         i = 0;
648         b = 0;
649         while (b <= ln) {
650             e = s.indexOf(c, b);
651             if (e == -1) e = ln;
652             res[i++] = s.substring(b, e);
653             b = e + 1;
654         }
655         return res;
656     }
657
658     /**
659      * Splits a string at the specified string.
660      */

661     public static String JavaDoc[] split(String JavaDoc s, String JavaDoc sep, boolean caseInsensitive) {
662         String JavaDoc splitString = caseInsensitive ? sep.toLowerCase() : sep;
663         String JavaDoc input = caseInsensitive ? s.toLowerCase() : s;
664         int i, b, e;
665         int cnt;
666         String JavaDoc res[];
667         int ln = s.length();
668         int sln = sep.length();
669
670         if (sln == 0) throw new IllegalArgumentException JavaDoc(
671                 "The separator string has 0 length");
672
673         i = 0;
674         cnt = 1;
675         while ((i = input.indexOf(splitString, i)) != -1) {
676             cnt++;
677             i += sln;
678         }
679         res = new String JavaDoc[cnt];
680
681         i = 0;
682         b = 0;
683         while (b <= ln) {
684             e = input.indexOf(splitString, b);
685             if (e == -1) e = ln;
686             res[i++] = s.substring(b, e);
687             b = e + sln;
688         }
689         return res;
690     }
691
692     /**
693      * Replaces all occurrences of a sub-string in a string.
694      * @param text The string where it will replace <code>oldsub</code> with
695      * <code>newsub</code>.
696      * @return String The string after the replacements.
697      */

698     public static String JavaDoc replace(String JavaDoc text,
699                                   String JavaDoc oldsub,
700                                   String JavaDoc newsub,
701                                   boolean caseInsensitive,
702                                   boolean firstOnly)
703     {
704         StringBuffer JavaDoc buf;
705         int tln;
706         int oln = oldsub.length();
707         
708         if (oln == 0) {
709             int nln = newsub.length();
710             if (nln == 0) {
711                 return text;
712             } else {
713                 if (firstOnly) {
714                     return newsub + text;
715                 } else {
716                     tln = text.length();
717                     buf = new StringBuffer JavaDoc(tln + (tln + 1) * nln);
718                     buf.append(newsub);
719                     for (int i = 0; i < tln; i++) {
720                         buf.append(text.charAt(i));
721                         buf.append(newsub);
722                     }
723                     return buf.toString();
724                 }
725             }
726         } else {
727             oldsub = caseInsensitive ? oldsub.toLowerCase() : oldsub;
728             String JavaDoc input = caseInsensitive ? text.toLowerCase() : text;
729             int e = input.indexOf(oldsub);
730             if (e == -1) {
731                 return text;
732             }
733             int b = 0;
734             tln = text.length();
735             buf = new StringBuffer JavaDoc(
736                     tln + Math.max(newsub.length() - oln, 0) * 3);
737             do {
738                 buf.append(text.substring(b, e));
739                 buf.append(newsub);
740                 b = e + oln;
741                 e = input.indexOf(oldsub, b);
742             } while (e != -1 && !firstOnly);
743             buf.append(text.substring(b));
744             return buf.toString();
745         }
746     }
747
748     /**
749      * Removes the line-break from the end of the string.
750      */

751     public static String JavaDoc chomp(String JavaDoc s) {
752         if (s.endsWith("\r\n")) return s.substring(0, s.length() - 2);
753         if (s.endsWith("\r") || s.endsWith("\n"))
754                 return s.substring(0, s.length() - 1);
755         return s;
756     }
757
758     /**
759      * Quotes string as Java Language string literal.
760      * Returns string <code>"null"</code> if <code>s</code>
761      * is <code>null</code>.
762      */

763     public static String JavaDoc jQuote(String JavaDoc s) {
764         if (s == null) {
765             return "null";
766         }
767         int ln = s.length();
768         StringBuffer JavaDoc b = new StringBuffer JavaDoc(ln + 4);
769         b.append('"');
770         for (int i = 0; i < ln; i++) {
771             char c = s.charAt(i);
772             if (c == '"') {
773                 b.append("\\\"");
774             } else if (c == '\\') {
775                 b.append("\\\\");
776             } else if (c < 0x20) {
777                 if (c == '\n') {
778                     b.append("\\n");
779                 } else if (c == '\r') {
780                     b.append("\\r");
781                 } else if (c == '\f') {
782                     b.append("\\f");
783                 } else if (c == '\b') {
784                     b.append("\\b");
785                 } else if (c == '\t') {
786                     b.append("\\t");
787                 } else {
788                     b.append("\\u00");
789                     int x = c / 0x10;
790                     b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A'));
791                     x = c & 0xF;
792                     b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A'));
793                 }
794             } else {
795                 b.append(c);
796             }
797         } // for each characters
798
b.append('"');
799         return b.toString();
800     }
801
802     /**
803      * Escapes the <code>String</code> with the escaping rules of Java language
804      * string literals, so it is safe to insert the value into a string literal.
805      * The resulting string will not be quoted.
806      *
807      * <p>In additional, all characters under UCS code point 0x20, that has no
808      * dedicated escape sequence in Java language, will be replaced with UNICODE
809      * escape (<tt>\<!-- -->u<i>XXXX</i></tt>).
810      *
811      * @see #jQuote(String)
812      */

813     public static String JavaDoc javaStringEnc(String JavaDoc s) {
814         int ln = s.length();
815         for (int i = 0; i < ln; i++) {
816             char c = s.charAt(i);
817             if (c == '"' || c == '\\' || c < 0x20) {
818                 StringBuffer JavaDoc b = new StringBuffer JavaDoc(ln + 4);
819                 b.append(s.substring(0, i));
820                 while (true) {
821                     if (c == '"') {
822                         b.append("\\\"");
823                     } else if (c == '\\') {
824                         b.append("\\\\");
825                     } else if (c < 0x20) {
826                         if (c == '\n') {
827                             b.append("\\n");
828                         } else if (c == '\r') {
829                             b.append("\\r");
830                         } else if (c == '\f') {
831                             b.append("\\f");
832                         } else if (c == '\b') {
833                             b.append("\\b");
834                         } else if (c == '\t') {
835                             b.append("\\t");
836                         } else {
837                             b.append("\\u00");
838                             int x = c / 0x10;
839                             b.append((char)
840                                     (x < 0xA ? x + '0' : x - 0xA + 'a'));
841                             x = c & 0xF;
842                             b.append((char)
843                                     (x < 0xA ? x + '0' : x - 0xA + 'a'));
844                         }
845                     } else {
846                         b.append(c);
847                     }
848                     i++;
849                     if (i >= ln) {
850                         return b.toString();
851                     }
852                     c = s.charAt(i);
853                 }
854             } // if has to be escaped
855
} // for each characters
856
return s;
857     }
858     
859     /**
860      * Escapes a <code>String</code> according the JavaScript string literal
861      * escaping rules. The resulting string will not be quoted.
862      *
863      * <p>It escapes both <tt>'</tt> and <tt>"</tt>.
864      * In additional it escapes <tt>></tt> as <tt>\></tt> (to avoid
865      * <tt>&lt;/script></tt>). Furthermore, all characters under UCS code point
866      * 0x20, that has no dedicated escape sequence in JavaScript language, will
867      * be replaced with hexadecimal escape (<tt>\x<i>XX</i></tt>).
868      */

869     public static String JavaDoc javaScriptStringEnc(String JavaDoc s) {
870         int ln = s.length();
871         for (int i = 0; i < ln; i++) {
872             char c = s.charAt(i);
873             if (c == '"' || c == '\'' || c == '\\' || c == '>' || c < 0x20) {
874                 StringBuffer JavaDoc b = new StringBuffer JavaDoc(ln + 4);
875                 b.append(s.substring(0, i));
876                 while (true) {
877                     if (c == '"') {
878                         b.append("\\\"");
879                     } else if (c == '\'') {
880                         b.append("\\'");
881                     } else if (c == '\\') {
882                         b.append("\\\\");
883                     } else if (c == '>') {
884                         b.append("\\>");
885                     } else if (c < 0x20) {
886                         if (c == '\n') {
887                             b.append("\\n");
888                         } else if (c == '\r') {
889                             b.append("\\r");
890                         } else if (c == '\f') {
891                             b.append("\\f");
892                         } else if (c == '\b') {
893                             b.append("\\b");
894                         } else if (c == '\t') {
895                             b.append("\\t");
896                         } else {
897                             b.append("\\x");
898                             int x = c / 0x10;
899                             b.append((char)
900                                     (x < 0xA ? x + '0' : x - 0xA + 'A'));
901                             x = c & 0xF;
902                             b.append((char)
903                                     (x < 0xA ? x + '0' : x - 0xA + 'A'));
904                         }
905                     } else {
906                         b.append(c);
907                     }
908                     i++;
909                     if (i >= ln) {
910                         return b.toString();
911                     }
912                     c = s.charAt(i);
913                 }
914             } // if has to be escaped
915
} // for each characters
916
return s;
917     }
918
919     /**
920      * Parses a name-value pair list, where the pairs are separated with comma,
921      * and the name and value is separated with colon.
922      * The keys and values can contain only letters, digits and <tt>_</tt>. They
923      * can't be quoted. White-space around the keys and values are ignored. The
924      * value can be omitted if <code>defaultValue</code> is not null. When a
925      * value is omitted, then the colon after the key must be omitted as well.
926      * The same key can't be used for multiple times.
927      *
928      * @param s the string to parse.
929      * For example: <code>"strong:100, soft:900"</code>.
930      * @param defaultValue the value used when the value is omitted in a
931      * key-value pair.
932      *
933      * @return the map that contains the name-value pairs.
934      *
935      * @throws java.text.ParseException if the string is not a valid name-value
936      * pair list.
937      */

938     public static Map parseNameValuePairList(String JavaDoc s, String JavaDoc defaultValue)
939     throws java.text.ParseException JavaDoc {
940         Map map = new HashMap();
941         
942         char c = ' ';
943         int ln = s.length();
944         int p = 0;
945         int keyStart;
946         int valueStart;
947         String JavaDoc key;
948         String JavaDoc value;
949         
950         fetchLoop: while (true) {
951             // skip ws
952
while (p < ln) {
953                 c = s.charAt(p);
954                 if (!Character.isWhitespace(c)) {
955                     break;
956                 }
957                 p++;
958             }
959             if (p == ln) {
960                 break fetchLoop;
961             }
962             keyStart = p;
963
964             // seek key end
965
while (p < ln) {
966                 c = s.charAt(p);
967                 if (!(Character.isLetterOrDigit(c) || c == '_')) {
968                     break;
969                 }
970                 p++;
971             }
972             if (keyStart == p) {
973                 throw new java.text.ParseException JavaDoc(
974                        "Expecting letter, digit or \"_\" "
975                         + "here, (the first character of the key) but found "
976                         + jQuote(String.valueOf(c))
977                         + " at position " + p + ".",
978                         p);
979             }
980             key = s.substring(keyStart, p);
981
982             // skip ws
983
while (p < ln) {
984                 c = s.charAt(p);
985                 if (!Character.isWhitespace(c)) {
986                     break;
987                 }
988                 p++;
989             }
990             if (p == ln) {
991                 if (defaultValue == null) {
992                     throw new java.text.ParseException JavaDoc(
993                             "Expecting \":\", but reached "
994                             + "the end of the string "
995                             + " at position " + p + ".",
996                             p);
997                 }
998                 value = defaultValue;
999             } else if (c != ':') {
1000                if (defaultValue == null || c != ',') {
1001                    throw new java.text.ParseException JavaDoc(
1002                            "Expecting \":\" here, but found "
1003                            + jQuote(String.valueOf(c))
1004                            + " at position " + p + ".",
1005                            p);
1006                }
1007
1008                // skip ","
1009
p++;
1010                
1011                value = defaultValue;
1012            } else {
1013                // skip ":"
1014
p++;
1015    
1016                // skip ws
1017
while (p < ln) {
1018                    c = s.charAt(p);
1019                    if (!Character.isWhitespace(c)) {
1020                        break;
1021                    }
1022                    p++;
1023                }
1024                if (p == ln) {
1025                    throw new java.text.ParseException JavaDoc(
1026                            "Expecting the value of the key "
1027                            + "here, but reached the end of the string "
1028                            + " at position " + p + ".",
1029                            p);
1030                }
1031                valueStart = p;
1032    
1033                // seek value end
1034
while (p < ln) {
1035                    c = s.charAt(p);
1036                    if (!(Character.isLetterOrDigit(c) || c == '_')) {
1037                        break;
1038                    }
1039                    p++;
1040                }
1041                if (valueStart == p) {
1042                    throw new java.text.ParseException JavaDoc(
1043                            "Expecting letter, digit or \"_\" "
1044                            + "here, (the first character of the value) "
1045                            + "but found "
1046                            + jQuote(String.valueOf(c))
1047                            + " at position " + p + ".",
1048                            p);
1049                }
1050                value = s.substring(valueStart, p);
1051
1052                // skip ws
1053
while (p < ln) {
1054                    c = s.charAt(p);
1055                    if (!Character.isWhitespace(c)) {
1056                        break;
1057                    }
1058                    p++;
1059                }
1060                
1061                // skip ","
1062
if (p < ln) {
1063                    if (c != ',') {
1064                        throw new java.text.ParseException JavaDoc(
1065                                "Excpecting \",\" or the end "
1066                                + "of the string here, but found "
1067                                + jQuote(String.valueOf(c))
1068                                + " at position " + p + ".",
1069                                p);
1070                    } else {
1071                        p++;
1072                    }
1073                }
1074            }
1075            
1076            // store the key-value pair
1077
if (map.put(key, value) != null) {
1078                throw new java.text.ParseException JavaDoc(
1079                        "Dublicated key: "
1080                        + jQuote(key), keyStart);
1081            }
1082        }
1083        
1084        return map;
1085    }
1086    
1087    /**
1088     * @return whether the name is a valid XML tagname.
1089     * (This routine might only be 99% accurate. Should maybe REVISIT)
1090     */

1091    static public boolean isXMLID(String JavaDoc name) {
1092        for (int i=0; i<name.length(); i++) {
1093            char c = name.charAt(i);
1094            if (i==0) {
1095                if (c== '-' || c=='.' || Character.isDigit(c))
1096                    return false;
1097            }
1098            if (!Character.isLetterOrDigit(c) && c != ':' && c != '_' && c != '-' && c!='.') {
1099                return false;
1100            }
1101        }
1102        return true;
1103    }
1104    
1105    /**
1106     * @return whether the qname matches the combination of nodeName, nsURI, and environment prefix settings.
1107     */

1108    
1109    static public boolean matchesName(String JavaDoc qname, String JavaDoc nodeName, String JavaDoc nsURI, Environment env) {
1110        String JavaDoc defaultNS = env.getDefaultNS();
1111        if ((defaultNS != null) && defaultNS.equals(nsURI)) {
1112            return qname.equals(nodeName)
1113               || qname.equals(Template.DEFAULT_NAMESPACE_PREFIX + ":" + nodeName);
1114        }
1115        if ("".equals(nsURI)) {
1116            if (defaultNS != null) {
1117                return qname.equals(Template.NO_NS_PREFIX + ":" + nodeName);
1118            } else {
1119                return qname.equals(nodeName) || qname.equals(Template.NO_NS_PREFIX + ":" + nodeName);
1120            }
1121        }
1122        String JavaDoc prefix = env.getPrefixForNamespace(nsURI);
1123        if (prefix == null) {
1124            return false; // Is this the right thing here???
1125
}
1126        return qname.equals(prefix + ":" + nodeName);
1127    }
1128    
1129    /**
1130     * Pads the string at the left with spaces until it reaches the desired
1131     * length. If the string is longer than this length, then it returns the
1132     * unchanged string.
1133     *
1134     * @param s the string that will be padded.
1135     * @param minLength the length to reach.
1136     */

1137    public static String JavaDoc leftPad(String JavaDoc s, int minLength) {
1138        return leftPad(s, minLength, ' ');
1139    }
1140    
1141    /**
1142     * Pads the string at the left with the specified character until it reaches
1143     * the desired length. If the string is longer than this length, then it
1144     * returns the unchanged string.
1145     *
1146     * @param s the string that will be padded.
1147     * @param minLength the length to reach.
1148     * @param filling the filling pattern.
1149     */

1150    public static String JavaDoc leftPad(String JavaDoc s, int minLength, char filling) {
1151        int ln = s.length();
1152        if (minLength <= ln) {
1153            return s;
1154        }
1155        
1156        StringBuffer JavaDoc res = new StringBuffer JavaDoc(minLength);
1157        
1158        int dif = minLength - ln;
1159        for (int i = 0; i < dif; i++) {
1160            res.append(filling);
1161        }
1162        
1163        res.append(s);
1164        
1165        return res.toString();
1166    }
1167
1168    /**
1169     * Pads the string at the left with a filling pattern until it reaches the
1170     * desired length. If the string is longer than this length, then it returns
1171     * the unchanged string. For example: <code>leftPad('ABC', 9, '1234')</code>
1172     * returns <code>"123412ABC"</code>.
1173     *
1174     * @param s the string that will be padded.
1175     * @param minLength the length to reach.
1176     * @param filling the filling pattern. Must be at least 1 characters long.
1177     * Can't be <code>null</code>.
1178     */

1179    public static String JavaDoc leftPad(String JavaDoc s, int minLength, String JavaDoc filling) {
1180        int ln = s.length();
1181        if (minLength <= ln) {
1182            return s;
1183        }
1184        
1185        StringBuffer JavaDoc res = new StringBuffer JavaDoc(minLength);
1186
1187        int dif = minLength - ln;
1188        int fln = filling.length();
1189        if (fln == 0) {
1190            throw new IllegalArgumentException JavaDoc(
1191                    "The \"filling\" argument can't be 0 length string.");
1192        }
1193        int cnt = dif / fln;
1194        for (int i = 0; i < cnt; i++) {
1195            res.append(filling);
1196        }
1197        cnt = dif % fln;
1198        for (int i = 0; i < cnt; i++) {
1199            res.append(filling.charAt(i));
1200        }
1201        
1202        res.append(s);
1203        
1204        return res.toString();
1205    }
1206    
1207    /**
1208     * Pads the string at the right with spaces until it reaches the desired
1209     * length. If the string is longer than this length, then it returns the
1210     * unchanged string.
1211     *
1212     * @param s the string that will be padded.
1213     * @param minLength the length to reach.
1214     */

1215    public static String JavaDoc rightPad(String JavaDoc s, int minLength) {
1216        return rightPad(s, minLength, ' ');
1217    }
1218    
1219    /**
1220     * Pads the string at the right with the specified character until it
1221     * reaches the desired length. If the string is longer than this length,
1222     * then it returns the unchanged string.
1223     *
1224     * @param s the string that will be padded.
1225     * @param minLength the length to reach.
1226     * @param filling the filling pattern.
1227     */

1228    public static String JavaDoc rightPad(String JavaDoc s, int minLength, char filling) {
1229        int ln = s.length();
1230        if (minLength <= ln) {
1231            return s;
1232        }
1233        
1234        StringBuffer JavaDoc res = new StringBuffer JavaDoc(minLength);
1235
1236        res.append(s);
1237        
1238        int dif = minLength - ln;
1239        for (int i = 0; i < dif; i++) {
1240            res.append(filling);
1241        }
1242        
1243        return res.toString();
1244    }
1245
1246    /**
1247     * Pads the string at the right with a filling pattern until it reaches the
1248     * desired length. If the string is longer than this length, then it returns
1249     * the unchanged string. For example: <code>rightPad('ABC', 9, '1234')</code>
1250     * returns <code>"ABC412341"</code>. Note that the filling pattern is
1251     * started as if you overlay <code>"123412341"</code> with the left-aligned
1252     * <code>"ABC"</code>, so it starts with <code>"4"</code>.
1253     *
1254     * @param s the string that will be padded.
1255     * @param minLength the length to reach.
1256     * @param filling the filling pattern. Must be at least 1 characters long.
1257     * Can't be <code>null</code>.
1258     */

1259    public static String JavaDoc rightPad(String JavaDoc s, int minLength, String JavaDoc filling) {
1260        int ln = s.length();
1261        if (minLength <= ln) {
1262            return s;
1263        }
1264        
1265        StringBuffer JavaDoc res = new StringBuffer JavaDoc(minLength);
1266
1267        res.append(s);
1268
1269        int dif = minLength - ln;
1270        int fln = filling.length();
1271        if (fln == 0) {
1272            throw new IllegalArgumentException JavaDoc(
1273                    "The \"filling\" argument can't be 0 length string.");
1274        }
1275        int start = ln % fln;
1276        int end = fln - start <= dif
1277                ? fln
1278                : start + dif;
1279        for (int i = start; i < end; i++) {
1280            res.append(filling.charAt(i));
1281        }
1282        dif -= end - start;
1283        int cnt = dif / fln;
1284        for (int i = 0; i < cnt; i++) {
1285            res.append(filling);
1286        }
1287        cnt = dif % fln;
1288        for (int i = 0; i < cnt; i++) {
1289            res.append(filling.charAt(i));
1290        }
1291        
1292        return res.toString();
1293    }
1294    
1295}
1296
Popular Tags