KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > util > CmsStringUtil


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/util/CmsStringUtil.java,v $
3  * Date : $Date: 2006/04/28 15:20:52 $
4  * Version: $Revision: 1.40 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.util;
33
34 import org.opencms.file.CmsResource;
35 import org.opencms.i18n.CmsEncoder;
36 import org.opencms.i18n.I_CmsMessageBundle;
37 import org.opencms.main.CmsIllegalArgumentException;
38 import org.opencms.main.CmsLog;
39
40 import java.awt.Color JavaDoc;
41 import java.nio.charset.Charset JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.regex.Matcher JavaDoc;
48 import java.util.regex.Pattern JavaDoc;
49
50 import org.apache.commons.logging.Log;
51 import org.apache.oro.text.perl.MalformedPerl5PatternException;
52 import org.apache.oro.text.perl.Perl5Util;
53
54 /**
55  * Provides String utility functions.<p>
56  *
57  * @author Andreas Zahner
58  * @author Alexander Kandzior
59  * @author Thomas Weckert
60  *
61  * @version $Revision: 1.40 $
62  *
63  * @since 6.0.0
64  */

65 public final class CmsStringUtil {
66
67     /** Regular expression that matches the HTML body end tag. */
68     public static final String JavaDoc BODY_END_REGEX = "<\\s*/\\s*body[^>]*>";
69
70     /** Regular expression that matches the HTML body start tag. */
71     public static final String JavaDoc BODY_START_REGEX = "<\\s*body[^>]*>";
72
73     /** Constant for <code>"false"</code>. */
74     public static final String JavaDoc FALSE = Boolean.toString(false);
75
76     /** a convienient shorthand to the line separator constant. */
77     public static final String JavaDoc LINE_SEPARATOR = System.getProperty("line.separator");
78
79     /** Context macro. */
80     public static final String JavaDoc MACRO_OPENCMS_CONTEXT = "${OpenCmsContext}";
81
82     /** a convienient shorthand for tabulations. */
83     public static final String JavaDoc TABULATOR = " ";
84
85     /** Constant for <code>"true"</code>. */
86     public static final String JavaDoc TRUE = Boolean.toString(true);
87
88     /** Regex pattern that matches an end body tag. */
89     private static final Pattern JavaDoc BODY_END_PATTERN = Pattern.compile(BODY_END_REGEX, Pattern.CASE_INSENSITIVE);
90
91     /** Regex pattern that matches a start body tag. */
92     private static final Pattern JavaDoc BODY_START_PATTERN = Pattern.compile(BODY_START_REGEX, Pattern.CASE_INSENSITIVE);
93
94     /** Day constant. */
95     private static final long DAYS = 1000 * 60 * 60 * 24;
96
97     /** Hour constant. */
98     private static final long HOURS = 1000 * 60 * 60;
99
100     /** The log object for this class. */
101     private static final Log LOG = CmsLog.getLog(CmsStringUtil.class);
102
103     /** OpenCms context replace String, static for performance reasons. */
104     private static String JavaDoc m_contextReplace;
105
106     /** OpenCms context search String, static for performance reasons. */
107     private static String JavaDoc m_contextSearch;
108
109     /** Minute constant. */
110     private static final long MINUTES = 1000 * 60;
111
112     /** Second constant. */
113     private static final long SECONDS = 1000;
114
115     /** Regex that matches an encoding String in an xml head. */
116     private static final Pattern JavaDoc XML_ENCODING_REGEX = Pattern.compile(
117         "encoding\\s*=\\s*[\"'].+[\"']",
118         Pattern.CASE_INSENSITIVE);
119
120     /** Regex that matches an xml head. */
121     private static final Pattern JavaDoc XML_HEAD_REGEX = Pattern.compile("<\\s*\\?.*\\?\\s*>", Pattern.CASE_INSENSITIVE);
122
123     /**
124      * Default constructor (empty), private because this class has only
125      * static methods.<p>
126      */

127     private CmsStringUtil() {
128
129         // empty
130
}
131
132     /**
133      * Changes the filename suffix.
134      *
135      * @param filename the filename to be changed
136      * @param suffix the new suffix of the file
137      * @return the filename with the replaced suffix
138      */

139     public static String JavaDoc changeFileNameSuffixTo(String JavaDoc filename, String JavaDoc suffix) {
140
141         int dotPos = filename.lastIndexOf('.');
142         if (dotPos != -1) {
143             return filename.substring(0, dotPos + 1) + suffix;
144         } else {
145             // the string has no suffix
146
return filename;
147         }
148     }
149
150     /**
151      * Checks if a given name is composed only of the characters <code>a...z,A...Z,0...9</code>
152      * and the provided <code>contraints</code>.<p>
153      *
154      * If the check fails, an Exception is generated. The provided bundle and key is
155      * used to generate the Exception. 4 parameters are passed to the Exception:<ol>
156      * <li>The <code>name</code>
157      * <li>The first illegal character found
158      * <li>The position where the illegal character was found
159      * <li>The <code>contraints</code></ol>
160      *
161      * @param name the name to check
162      * @param contraints the additional character contraints
163      * @param key the key to use for generating the Exception (if required)
164      * @param bundle the bundle to use for generating the Exception (if required)
165      *
166      * @throws CmsIllegalArgumentException if the check fails (generated from the given key and bundle)
167      */

168     public static void checkName(String JavaDoc name, String JavaDoc contraints, String JavaDoc key, I_CmsMessageBundle bundle)
169     throws CmsIllegalArgumentException {
170
171         int l = name.length();
172         for (int i = 0; i < l; i++) {
173             char c = name.charAt(i);
174             if (((c < 'a') || (c > 'z'))
175                 && ((c < '0') || (c > '9'))
176                 && ((c < 'A') || (c > 'Z'))
177                 && (contraints.indexOf(c) < 0)) {
178
179                 throw new CmsIllegalArgumentException(bundle.container(key, new Object JavaDoc[] {
180                     name,
181                     new Character JavaDoc(c),
182                     new Integer JavaDoc(i),
183                     contraints}));
184             }
185         }
186     }
187
188     /**
189      * Replaces occurences of special control characters in the given input with
190      * a HTML representation.<p>
191      *
192      * This method currrently replaces line breaks to <code>&lt;br/&gt;</code> and special HTML chars
193      * like <code>&lt; &gt; &amp; &quot;</code> with their HTML entity representation.<p>
194      *
195      * @param source the String to escape
196      * @return the escaped String
197      */

198     public static String JavaDoc escapeHtml(String JavaDoc source) {
199
200         if (source == null) {
201             return null;
202         }
203         source = CmsEncoder.escapeXml(source);
204         source = CmsStringUtil.substitute(source, "\r", "");
205         source = CmsStringUtil.substitute(source, "\n", "<br/>\n");
206         return source;
207     }
208
209     /**
210      * Escapes a String so it may be used in JavaScript String definitions.<p>
211      *
212      * This method replaces line breaks, quotationmarks and \ characters.<p>
213      *
214      * @param source the String to escape
215      * @return the escaped String
216      */

217     public static String JavaDoc escapeJavaScript(String JavaDoc source) {
218
219         source = CmsStringUtil.substitute(source, "\\", "\\\\");
220         source = CmsStringUtil.substitute(source, "\"", "\\\"");
221         source = CmsStringUtil.substitute(source, "\'", "\\\'");
222         source = CmsStringUtil.substitute(source, "\r\n", "\\n");
223         source = CmsStringUtil.substitute(source, "\n", "\\n");
224         return source;
225     }
226
227     /**
228      * Escapes a String so it may be used as a Perl5 regular expression.<p>
229      *
230      * This method replaces the following characters in a String:<br>
231      * <code>{}[]()\$^.*+/</code>
232      *
233      *
234      * @param source the string to escape
235      * @return the escaped string
236      */

237     public static String JavaDoc escapePattern(String JavaDoc source) {
238
239         if (source == null) {
240             return null;
241         }
242         StringBuffer JavaDoc result = new StringBuffer JavaDoc(source.length() * 2);
243         for (int i = 0; i < source.length(); ++i) {
244             char ch = source.charAt(i);
245             switch (ch) {
246                 case '\\':
247                     result.append("\\\\");
248                     break;
249                 case '/':
250                     result.append("\\/");
251                     break;
252                 case '$':
253                     result.append("\\$");
254                     break;
255                 case '^':
256                     result.append("\\^");
257                     break;
258                 case '.':
259                     result.append("\\.");
260                     break;
261                 case '*':
262                     result.append("\\*");
263                     break;
264                 case '+':
265                     result.append("\\+");
266                     break;
267                 case '|':
268                     result.append("\\|");
269                     break;
270                 case '?':
271                     result.append("\\?");
272                     break;
273                 case '{':
274                     result.append("\\{");
275                     break;
276                 case '}':
277                     result.append("\\}");
278                     break;
279                 case '[':
280                     result.append("\\[");
281                     break;
282                 case ']':
283                     result.append("\\]");
284                     break;
285                 case '(':
286                     result.append("\\(");
287                     break;
288                 case ')':
289                     result.append("\\)");
290                     break;
291                 default:
292                     result.append(ch);
293             }
294         }
295         return new String JavaDoc(result);
296     }
297
298     /**
299      * This method takes a part of a html tag definition, an attribute to extend within the
300      * given text and a default value for this attribute; and returns a <code>{@link Map}</code>
301      * with 2 values: a <code>{@link String}</code> with key <code>"text"</code> with the new text
302      * without the given attribute, and another <code>{@link String}</code> with key <code>"value"</code>
303      * with the new extended value for the given attribute, this value is sourrounded by the same type of
304      * quotation marks as in the given text.<p>
305      *
306      * @param text the text to search in
307      * @param attribute the attribute to remove and extend from the text
308      * @param defValue a default value for the attribute, should not have any quotation mark
309      *
310      * @return a map with the new text and the new value for the given attribute
311      */

312     public static Map JavaDoc extendAttribute(String JavaDoc text, String JavaDoc attribute, String JavaDoc defValue) {
313
314         Map JavaDoc retValue = new HashMap JavaDoc();
315         retValue.put("text", text);
316         retValue.put("value", "'" + defValue + "'");
317         if (text != null && text.toLowerCase().indexOf(attribute.toLowerCase()) >= 0) {
318             // this doesnot work for things like "att=method()" without quotations.
319
String JavaDoc quotation = "\'";
320             int pos1 = text.toLowerCase().indexOf(attribute.toLowerCase());
321             // looking for the opening quotation mark
322
int pos2 = text.indexOf(quotation, pos1);
323             int test = text.indexOf("\"", pos1);
324             if (test > -1 && (pos2 == -1 || test < pos2)) {
325                 quotation = "\"";
326                 pos2 = test;
327             }
328             // assuming there is a closing quotation mark
329
int pos3 = text.indexOf(quotation, pos2 + 1);
330             // building the new attribute value
331
String JavaDoc newValue = quotation + defValue + text.substring(pos2 + 1, pos3 + 1);
332             // removing the onload statement from the parameters
333
String JavaDoc newText = text.substring(0, pos1);
334             if (pos3 < text.length()) {
335                 newText += text.substring(pos3 + 1);
336             }
337             retValue.put("text", newText);
338             retValue.put("value", newValue);
339         }
340         return retValue;
341     }
342
343     /**
344      * Extracts the content of a &lt;body&gt tag in a HTML page.<p>
345      *
346      * This method should be pretty robust and work even if the input HTML does not contains
347      * a valid body tag.<p>
348      *
349      * @param content the content to extract the body from
350      * @return the extracted body tag content
351      */

352     public static String JavaDoc extractHtmlBody(String JavaDoc content) {
353
354         Matcher JavaDoc startMatcher = BODY_START_PATTERN.matcher(content);
355         Matcher JavaDoc endMatcher = BODY_END_PATTERN.matcher(content);
356
357         int start = 0;
358         int end = content.length();
359
360         if (startMatcher.find()) {
361             start = startMatcher.end();
362         }
363
364         if (endMatcher.find(start)) {
365             end = endMatcher.start();
366         }
367
368         return content.substring(start, end);
369     }
370
371     /**
372      * Extracts the xml encoding setting from an xml file that is contained in a String by parsing
373      * the xml head.<p>
374      *
375      * This is useful if you have a byte array that contains a xml String,
376      * but you do not know the xml encoding setting. Since the encoding setting
377      * in the xml head is usually encoded with standard US-ASCII, you usually
378      * just create a String of the byte array without encoding setting,
379      * and use this method to find the 'true' encoding. Then create a String
380      * of the byte array again, this time using the found encoding.<p>
381      *
382      * This method will return <code>null</code> in case no xml head
383      * or encoding information is contained in the input.<p>
384      *
385      * @param content the xml content to extract the encoding from
386      * @return the extracted encoding, or null if no xml encoding setting was found in the input
387      */

388     public static String JavaDoc extractXmlEncoding(String JavaDoc content) {
389
390         String JavaDoc result = null;
391         Matcher JavaDoc xmlHeadMatcher = XML_HEAD_REGEX.matcher(content);
392         if (xmlHeadMatcher.find()) {
393             String JavaDoc xmlHead = xmlHeadMatcher.group();
394             Matcher JavaDoc encodingMatcher = XML_ENCODING_REGEX.matcher(xmlHead);
395             if (encodingMatcher.find()) {
396                 String JavaDoc encoding = encodingMatcher.group();
397                 int pos1 = encoding.indexOf('=') + 2;
398                 String JavaDoc charset = encoding.substring(pos1, encoding.length() - 1);
399                 if (Charset.isSupported(charset)) {
400                     result = charset;
401                 }
402             }
403         }
404         return result;
405     }
406
407     /**
408      * Formats a resource name that it is displayed with the maximum length and path information is adjusted.<p>
409      *
410      * Example: formatResourceName("/myfolder/subfolder/index.html", 21) returns <code>/.../subfolder/index.html</code>.<p>
411      * @param name the resource name to format
412      * @param maxLength the maximum length of the resource name (without leading <code>/...</code>)
413      * @return the formatted resource name
414      */

415     public static String JavaDoc formatResourceName(String JavaDoc name, int maxLength) {
416
417         if (name == null) {
418             return null;
419         }
420         if (name.length() <= maxLength) {
421             return name;
422         }
423
424         String JavaDoc result = CmsResource.getName(name);
425         name = CmsResource.getParentFolder(name);
426         while (name != null) {
427             String JavaDoc part = CmsResource.getName(name);
428
429             if ((part.length() + result.length()) <= maxLength) {
430                 result = part + result;
431             } else {
432                 result = "/" + result;
433                 if (!part.equals("/")) {
434                     result = "/..." + result;
435                 }
436                 break;
437             }
438             name = CmsResource.getParentFolder(name);
439         }
440
441         return result;
442     }
443
444     /**
445      * Formats a runtime in the format hh:mm:ss, to be used e.g. in reports.<p>
446      *
447      * If the runtime is greater then 24 hours, the format dd:hh:mm:ss is used.<p>
448      *
449      * @param runtime the time to format
450      * @return the formatted runtime
451      */

452     public static String JavaDoc formatRuntime(long runtime) {
453
454         long seconds = (runtime / SECONDS) % 60;
455         long minutes = (runtime / MINUTES) % 60;
456         long hours = (runtime / HOURS) % 24;
457         long days = runtime / DAYS;
458         StringBuffer JavaDoc strBuf = new StringBuffer JavaDoc();
459
460         if (days > 0) {
461             if (days < 10) {
462                 strBuf.append('0');
463             }
464             strBuf.append(days);
465             strBuf.append(':');
466         }
467
468         if (hours < 10) {
469             strBuf.append('0');
470         }
471         strBuf.append(hours);
472         strBuf.append(':');
473
474         if (minutes < 10) {
475             strBuf.append('0');
476         }
477         strBuf.append(minutes);
478         strBuf.append(':');
479
480         if (seconds < 10) {
481             strBuf.append('0');
482         }
483         strBuf.append(seconds);
484
485         return strBuf.toString();
486     }
487
488     /**
489      * Returns the color value (<code>{@link Color}</code>) for the given String value.<p>
490      *
491      * All parse errors are caught and the given default value is returned in this case.<p>
492      *
493      * @param value the value to parse as color
494      * @param defaultValue the default value in case of parsing errors
495      * @param key a key to be included in the debug output in case of parse errors
496      *
497      * @return the int value for the given parameter value String
498      */

499     public static Color JavaDoc getColorValue(String JavaDoc value, Color JavaDoc defaultValue, String JavaDoc key) {
500
501         Color JavaDoc result;
502         try {
503             char pre = value.charAt(0);
504             if (pre != '#') {
505                 value = "#" + value;
506             }
507             result = Color.decode(value);
508         } catch (Exception JavaDoc e) {
509             if (LOG.isDebugEnabled()) {
510                 LOG.debug(Messages.get().getBundle().key(Messages.ERR_UNABLE_TO_PARSE_COLOR_2, value, key));
511             }
512             result = defaultValue;
513         }
514         return result;
515     }
516
517     /**
518      * Returns the Integer (int) value for the given String value.<p>
519      *
520      * All parse errors are caught and the given default value is returned in this case.<p>
521      *
522      * @param value the value to parse as int
523      * @param defaultValue the default value in case of parsing errors
524      * @param key a key to be included in the debug output in case of parse errors
525      *
526      * @return the int value for the given parameter value String
527      */

528     public static int getIntValue(String JavaDoc value, int defaultValue, String JavaDoc key) {
529
530         int result;
531         try {
532             result = Integer.valueOf(value).intValue();
533         } catch (Exception JavaDoc e) {
534             if (LOG.isDebugEnabled()) {
535                 LOG.debug(Messages.get().getBundle().key(Messages.ERR_UNABLE_TO_PARSE_INT_2, value, key));
536             }
537             result = defaultValue;
538         }
539         return result;
540     }
541
542     /**
543      * Returns <code>true</code> if the provided String is either <code>null</code>
544      * or the empty String <code>""</code>.<p>
545      *
546      * @param value the value to check
547      * @return true, if the provided value is null or the empty String, false otherwise
548      */

549     public static boolean isEmpty(String JavaDoc value) {
550
551         return (value == null) || (value.length() == 0);
552     }
553
554     /**
555      * Returns <code>true</code> if the provided String is either <code>null</code>
556      * or contains only white spaces.<p>
557      *
558      * @param value the value to check
559      * @return true, if the provided value is null or contains only white spaces, false otherwise
560      */

561     public static boolean isEmptyOrWhitespaceOnly(String JavaDoc value) {
562
563         return isEmpty(value) || (value.trim().length() == 0);
564     }
565
566     /**
567      * Returns <code>true</code> if the provided String is neither <code>null</code>
568      * nor the empty String <code>""</code>.<p>
569      *
570      * @param value the value to check
571      * @return true, if the provided value is not null and not the empty String, false otherwise
572      */

573     public static boolean isNotEmpty(String JavaDoc value) {
574
575         return (value != null) && (value.length() != 0);
576     }
577
578     /**
579      * Returns <code>true</code> if the provided String is neither <code>null</code>
580      * nor contains only white spaces.<p>
581      *
582      * @param value the value to check
583      * @return true, if the provided value is null or contains only white spaces, false otherwise
584      */

585     public static boolean isNotEmptyOrWhitespaceOnly(String JavaDoc value) {
586
587         return (value != null) && (value.trim().length() > 0);
588     }
589
590     /**
591      * Checks if the given class name is a valid Java class name.<p>
592      *
593      * @param className the name to check
594      * @return true if the given class name is a valid Java class name
595      */

596     public static boolean isValidJavaClassName(String JavaDoc className) {
597
598         if (CmsStringUtil.isEmpty(className)) {
599             return false;
600         }
601         int length = className.length();
602         boolean nodot = true;
603         for (int i = 0; i < length; i++) {
604             char ch = className.charAt(i);
605             if (nodot) {
606                 if (ch == '.') {
607                     return false;
608                 } else if (Character.isJavaIdentifierStart(ch)) {
609                     nodot = false;
610                 } else {
611                     return false;
612                 }
613             } else {
614                 if (ch == '.') {
615                     nodot = true;
616                 } else if (Character.isJavaIdentifierPart(ch)) {
617                     nodot = false;
618                 } else {
619                     return false;
620                 }
621             }
622         }
623         return true;
624     }
625
626     /**
627      * Applies white space padding to the left of the given String.<p>
628      *
629      * @param input the input to pad left
630      * @param size the size of the padding
631      *
632      * @return the input padded to the left
633      */

634     public static String JavaDoc padLeft(String JavaDoc input, int size) {
635
636         return (new PrintfFormat("%" + size + "s")).sprintf(input);
637     }
638
639     /**
640      * Applies white space padding to the right of the given String.<p>
641      *
642      * @param input the input to pad right
643      * @param size the size of the padding
644      *
645      * @return the input padded to the right
646      */

647     public static String JavaDoc padRight(String JavaDoc input, int size) {
648
649         return (new PrintfFormat("%-" + size + "s")).sprintf(input);
650     }
651
652     /**
653      * Splits a String into substrings along the provided char delimiter and returns
654      * the result as an Array of Substrings.<p>
655      *
656      * @param source the String to split
657      * @param delimiter the delimiter to split at
658      *
659      * @return the Array of splitted Substrings
660      */

661     public static String JavaDoc[] splitAsArray(String JavaDoc source, char delimiter) {
662
663         List JavaDoc result = splitAsList(source, delimiter);
664         return (String JavaDoc[])result.toArray(new String JavaDoc[result.size()]);
665     }
666
667     /**
668      * Splits a String into substrings along the provided String delimiter and returns
669      * the result as an Array of Substrings.<p>
670      *
671      * @param source the String to split
672      * @param delimiter the delimiter to split at
673      *
674      * @return the Array of splitted Substrings
675      */

676     public static String JavaDoc[] splitAsArray(String JavaDoc source, String JavaDoc delimiter) {
677
678         List JavaDoc result = splitAsList(source, delimiter);
679         return (String JavaDoc[])result.toArray(new String JavaDoc[result.size()]);
680     }
681
682     /**
683      * Splits a String into substrings along the provided char delimiter and returns
684      * the result as a List of Substrings.<p>
685      *
686      * @param source the String to split
687      * @param delimiter the delimiter to split at
688      *
689      * @return the List of splitted Substrings
690      */

691     public static List JavaDoc splitAsList(String JavaDoc source, char delimiter) {
692
693         return splitAsList(source, delimiter, false);
694     }
695
696     /**
697      * Splits a String into substrings along the provided char delimiter and returns
698      * the result as a List of Substrings.<p>
699      *
700      * @param source the String to split
701      * @param delimiter the delimiter to split at
702      * @param trim flag to indicate if leading and trailing whitespaces should be omitted
703      *
704      * @return the List of splitted Substrings
705      */

706     public static List JavaDoc splitAsList(String JavaDoc source, char delimiter, boolean trim) {
707
708         List JavaDoc result = new ArrayList JavaDoc();
709         int i = 0;
710         int l = source.length();
711         int n = source.indexOf(delimiter);
712         while (n != -1) {
713             // zero - length items are not seen as tokens at start or end
714
if ((i < n) || (i > 0) && (i < l)) {
715                 result.add(trim ? source.substring(i, n).trim() : source.substring(i, n));
716             }
717             i = n + 1;
718             n = source.indexOf(delimiter, i);
719         }
720         // is there a non - empty String to cut from the tail?
721
if (n < 0) {
722             n = source.length();
723         }
724         if (i < n) {
725             result.add(trim ? source.substring(i).trim() : source.substring(i));
726         }
727         return result;
728     }
729
730     /**
731      * Splits a String into substrings along the provided String delimiter and returns
732      * the result as List of Substrings.<p>
733      *
734      * @param source the String to split
735      * @param delimiter the delimiter to split at
736      *
737      * @return the Array of splitted Substrings
738      */

739     public static List JavaDoc splitAsList(String JavaDoc source, String JavaDoc delimiter) {
740
741         return splitAsList(source, delimiter, false);
742     }
743
744     /**
745      * Splits a String into substrings along the provided String delimiter and returns
746      * the result as List of Substrings.<p>
747      *
748      * @param source the String to split
749      * @param delimiter the delimiter to split at
750      * @param trim flag to indicate if leading and trailing whitespaces should be omitted
751      *
752      * @return the Array of splitted Substrings
753      */

754     public static List JavaDoc splitAsList(String JavaDoc source, String JavaDoc delimiter, boolean trim) {
755
756         int dl = delimiter.length();
757         if (dl == 1) {
758             // optimize for short strings
759
return splitAsList(source, delimiter.charAt(0), trim);
760         }
761
762         List JavaDoc result = new ArrayList JavaDoc();
763         int i = 0;
764         int l = source.length();
765         int n = source.indexOf(delimiter);
766         while (n != -1) {
767             // zero - length items are not seen as tokens at start or end: ",," is one empty token but not three
768
if ((i < n) || (i > 0) && (i < l)) {
769                 result.add(trim ? source.substring(i, n).trim() : source.substring(i, n));
770             }
771             i = n + dl;
772             n = source.indexOf(delimiter, i);
773         }
774         // is there a non - empty String to cut from the tail?
775
if (n < 0) {
776             n = source.length();
777         }
778         if (i < n) {
779             result.add(trim ? source.substring(i).trim() : source.substring(i));
780         }
781         return result;
782     }
783
784     /**
785      * Replaces a set of <code>searchString</code> and <code>replaceString</code> pairs,
786      * given by the <code>substitutions</code> Map parameter.<p>
787      *
788      * @param source the constent which is scanned
789      * @param substitions the map of substitutions
790      *
791      * @return the substituted String
792      *
793      * @see #substitute(String, String, String)
794      */

795     public static String JavaDoc substitute(String JavaDoc source, Map JavaDoc substitions) {
796
797         String JavaDoc result = source;
798         Iterator JavaDoc it = substitions.keySet().iterator();
799         while (it.hasNext()) {
800             String JavaDoc key = it.next().toString();
801             result = substitute(result, key, substitions.get(key).toString());
802         }
803         return result;
804     }
805
806     /**
807      * Substitutes <code>searchString</code> in the given source String with <code>replaceString</code>.<p>
808      *
809      * This is a high-performance implementation which should be used as a replacement for
810      * <code>{@link String#replaceAll(java.lang.String, java.lang.String)}</code> in case no
811      * regular expression evaluation is required.<p>
812      *
813      * @param source the content which is scanned
814      * @param searchString the String which is searched in content
815      * @param replaceString the String which replaces <code>searchString</code>
816      *
817      * @return the substituted String
818      */

819     public static String JavaDoc substitute(String JavaDoc source, String JavaDoc searchString, String JavaDoc replaceString) {
820
821         if (source == null) {
822             return null;
823         }
824
825         if (isEmpty(searchString)) {
826             return source;
827         }
828
829         if (replaceString == null) {
830             replaceString = "";
831         }
832         int len = source.length();
833         int sl = searchString.length();
834         int rl = replaceString.length();
835         int length;
836         if (sl == rl) {
837             length = len;
838         } else {
839             int c = 0;
840             int s = 0;
841             int e;
842             while ((e = source.indexOf(searchString, s)) != -1) {
843                 c++;
844                 s = e + sl;
845             }
846             if (c == 0) {
847                 return source;
848             }
849             length = len - (c * (sl - rl));
850         }
851
852         int s = 0;
853         int e = source.indexOf(searchString, s);
854         if (e == -1) {
855             return source;
856         }
857         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(length);
858         while (e != -1) {
859             sb.append(source.substring(s, e));
860             sb.append(replaceString);
861             s = e + sl;
862             e = source.indexOf(searchString, s);
863         }
864         e = len;
865         sb.append(source.substring(s, e));
866         return sb.toString();
867     }
868
869     /**
870      * Substitutes the OpenCms context path (e.g. /opencms/opencms/) in a HTML page with a
871      * special variable so that the content also runs if the context path of the server changes.<p>
872      *
873      * @param htmlContent the HTML to replace the context path in
874      * @param context the context path of the server
875      * @return the HTML with the replaced context path
876      */

877     public static String JavaDoc substituteContextPath(String JavaDoc htmlContent, String JavaDoc context) {
878
879         if (m_contextSearch == null) {
880             m_contextSearch = "([^\\w/])" + context;
881             m_contextReplace = "$1" + CmsStringUtil.escapePattern(CmsStringUtil.MACRO_OPENCMS_CONTEXT) + "/";
882         }
883         return substitutePerl(htmlContent, m_contextSearch, m_contextReplace, "g");
884     }
885
886     /**
887      * Substitutes searchString in content with replaceItem.<p>
888      *
889      * @param content the content which is scanned
890      * @param searchString the String which is searched in content
891      * @param replaceItem the new String which replaces searchString
892      * @param occurences must be a "g" if all occurences of searchString shall be replaced
893      * @return String the substituted String
894      */

895     public static String JavaDoc substitutePerl(String JavaDoc content, String JavaDoc searchString, String JavaDoc replaceItem, String JavaDoc occurences) {
896
897         String JavaDoc translationRule = "s#" + searchString + "#" + replaceItem + "#" + occurences;
898         Perl5Util perlUtil = new Perl5Util();
899         try {
900             return perlUtil.substitute(translationRule, content);
901         } catch (MalformedPerl5PatternException e) {
902             if (LOG.isDebugEnabled()) {
903                 LOG.debug(Messages.get().getBundle().key(Messages.LOG_MALFORMED_TRANSLATION_RULE_1, translationRule), e);
904             }
905         }
906         return content;
907     }
908
909     /**
910      * Returns the java String literal for the given String. <p>
911      *
912      * This is the form of the String that had to be written into sourcecode
913      * using the unicode escape sequence for special characters. <p>
914      *
915      * Example: "Ä" would be transformed to "\\u00C4".<p>
916      *
917      * @param s a string that may contain non-ascii characters
918      *
919      * @return the java unicode escaped string Literal of the given input string
920      */

921     public static String JavaDoc toUnicodeLiteral(String JavaDoc s) {
922
923         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
924         char[] carr = s.toCharArray();
925
926         String JavaDoc unicode;
927         for (int i = 0; i < carr.length; i++) {
928             result.append("\\u");
929             // append leading zeros
930
unicode = Integer.toHexString(carr[i]).toUpperCase();
931             for (int j = 4 - unicode.length(); j > 0; j--) {
932                 result.append("0");
933             }
934             result.append(unicode);
935         }
936         return result.toString();
937     }
938
939     /**
940      * Returns a substring of string source, which is at most length characters long.<p>
941      *
942      * @param source the string to trim
943      * @param length the maximum length of the string to be returned
944      *
945      * @return a substring of string source, which is at most length characters long
946      */

947     public static String JavaDoc trimToSize(String JavaDoc source, int length) {
948
949         int end = 0;
950         int newend;
951         while (true) {
952             newend = source.indexOf(" ", end);
953             if (newend > length && end > 0) {
954                 return source.substring(0, length - 3) + "...";
955             } else if (newend == -1) {
956                 if (length < source.length()) {
957                     return source.substring(0, length - 3) + "...";
958                 } else {
959                     return source;
960                 }
961             } else {
962                 end = newend + 1;
963             }
964         }
965     }
966
967     /**
968      * Validates a value against a regular expression.<p>
969      *
970      * @param value the value to test
971      * @param regex the regular expression
972      * @param allowEmpty if an empty value is allowed
973      *
974      * @return <code>true</code> if the value satisfies the validation
975      */

976     public static boolean validateRegex(String JavaDoc value, String JavaDoc regex, boolean allowEmpty) {
977
978         if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
979             return allowEmpty;
980         }
981         Pattern JavaDoc pattern = Pattern.compile(regex);
982         Matcher JavaDoc matcher = pattern.matcher(value);
983         return matcher.matches();
984     }
985
986     /**
987      * Checks if the provided name is a valid resource name, that is contains only
988      * valid characters.<p>
989      *
990      * PLEASE NOTE:
991      * This logic is NOT yet used in the current release.<p>
992      *
993      * @param name the resource name to check
994      * @return true if the resource name is vaild, false otherwise
995      */

996     public static boolean validateResourceName(String JavaDoc name) {
997
998         if (name == null) {
999             return false;
1000        }
1001        int l = name.length();
1002        if (l == 0) {
1003            return false;
1004        }
1005        if (name.length() != name.trim().length()) {
1006            // leading or trainling white space are not allowed
1007
return false;
1008        }
1009        for (int i = 0; i < l; i++) {
1010            char ch = name.charAt(i);
1011            switch (ch) {
1012                case '/':
1013                    return false;
1014                case '\\':
1015                    return false;
1016                case ':':
1017                    return false;
1018                case '*':
1019                    return false;
1020                case '?':
1021                    return false;
1022                case '"':
1023                    return false;
1024                case '>':
1025                    return false;
1026                case '<':
1027                    return false;
1028                case '|':
1029                    return false;
1030                default:
1031                    // ISO control chars are not allowed
1032
if (Character.isISOControl(ch)) {
1033                        return false;
1034                    }
1035                    // chars not defined in unicode are not allowed
1036
if (!Character.isDefined(ch)) {
1037                        return false;
1038                    }
1039            }
1040        }
1041
1042        return true;
1043    }
1044}
Popular Tags