001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.fulcrum.yaafi.framework.util;
021    
022    import java.util.Map;
023    
024    
025    /**
026     * A subset of the utilities available in commons-lang-2.1 StringUtils.
027     *
028     * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
029     */
030    public class StringUtils
031    {
032        // Replacing
033        //-----------------------------------------------------------------------
034        /**
035         * <p>Replaces a String with another String inside a larger String, once.</p>
036         *
037         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
038         *
039         * <pre>
040         * StringUtils.replaceOnce(null, *, *)        = null
041         * StringUtils.replaceOnce("", *, *)          = ""
042         * StringUtils.replaceOnce("aba", null, null) = "aba"
043         * StringUtils.replaceOnce("aba", null, null) = "aba"
044         * StringUtils.replaceOnce("aba", "a", null)  = "aba"
045         * StringUtils.replaceOnce("aba", "a", "")    = "aba"
046         * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
047         * </pre>
048         *
049         * @see #replace(String text, String repl, String with, int max)
050         * @param text  text to search and replace in, may be null
051         * @param repl  the String to search for, may be null
052         * @param with  the String to replace with, may be null
053         * @return the text with any replacements processed,
054         *  <code>null</code> if null String input
055         */
056        public static String replaceOnce(String text, String repl, String with) {
057            return replace(text, repl, with, 1);
058        }
059    
060        /**
061         * <p>Replaces all occurrences of a String within another String.</p>
062         *
063         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
064         *
065         * <pre>
066         * StringUtils.replace(null, *, *)        = null
067         * StringUtils.replace("", *, *)          = ""
068         * StringUtils.replace("aba", null, null) = "aba"
069         * StringUtils.replace("aba", null, null) = "aba"
070         * StringUtils.replace("aba", "a", null)  = "aba"
071         * StringUtils.replace("aba", "a", "")    = "aba"
072         * StringUtils.replace("aba", "a", "z")   = "zbz"
073         * </pre>
074         *
075         * @see #replace(String text, String repl, String with, int max)
076         * @param text  text to search and replace in, may be null
077         * @param repl  the String to search for, may be null
078         * @param with  the String to replace with, may be null
079         * @return the text with any replacements processed,
080         *  <code>null</code> if null String input
081         */
082        public static String replace(String text, String repl, String with) {
083            return replace(text, repl, with, -1);
084        }
085    
086        /**
087         * <p>Replaces a String with another String inside a larger String,
088         * for the first <code>max</code> values of the search String.</p>
089         *
090         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
091         *
092         * <pre>
093         * StringUtils.replace(null, *, *, *)         = null
094         * StringUtils.replace("", *, *, *)           = ""
095         * StringUtils.replace("abaa", null, null, 1) = "abaa"
096         * StringUtils.replace("abaa", null, null, 1) = "abaa"
097         * StringUtils.replace("abaa", "a", null, 1)  = "abaa"
098         * StringUtils.replace("abaa", "a", "", 1)    = "abaa"
099         * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
100         * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
101         * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
102         * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
103         * </pre>
104         *
105         * @param text  text to search and replace in, may be null
106         * @param repl  the String to search for, may be null
107         * @param with  the String to replace with, may be null
108         * @param max  maximum number of values to replace, or <code>-1</code> if no maximum
109         * @return the text with any replacements processed,
110         *  <code>null</code> if null String input
111         */
112        public static String replace(String text, String repl, String with, int max) {
113            if (text == null || repl == null || with == null || repl.length() == 0 || max == 0) {
114                return text;
115            }
116    
117            StringBuffer buf = new StringBuffer(text.length());
118            int start = 0, end = 0;
119            while ((end = text.indexOf(repl, start)) != -1) {
120                buf.append(text.substring(start, end)).append(with);
121                start = end + repl.length();
122    
123                if (--max == 0) {
124                    break;
125                }
126            }
127            buf.append(text.substring(start));
128            return buf.toString();
129        }
130    
131        // Replace, character based
132        //-----------------------------------------------------------------------
133        /**
134         * <p>Replaces all occurrences of a character in a String with another.
135         * This is a null-safe version of {@link String#replace(char, char)}.</p>
136         *
137         * <p>A <code>null</code> string input returns <code>null</code>.
138         * An empty ("") string input returns an empty string.</p>
139         *
140         * <pre>
141         * StringUtils.replaceChars(null, *, *)        = null
142         * StringUtils.replaceChars("", *, *)          = ""
143         * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
144         * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
145         * </pre>
146         *
147         * @param str  String to replace characters in, may be null
148         * @param searchChar  the character to search for, may be null
149         * @param replaceChar  the character to replace, may be null
150         * @return modified String, <code>null</code> if null string input
151         * @since 2.0
152         */
153        public static String replaceChars(String str, char searchChar,
154            char replaceChar)
155        {
156            if (str == null)
157            {
158                return null;
159            }
160            return str.replace( searchChar, replaceChar );
161        }
162    
163        /**
164         * <p>Replaces multiple characters in a String in one go.
165         * This method can also be used to delete characters.</p>
166         *
167         * <p>For example:<br />
168         * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
169         *
170         * <p>A <code>null</code> string input returns <code>null</code>.
171         * An empty ("") string input returns an empty string.
172         * A null or empty set of search characters returns the input string.</p>
173         *
174         * <p>The length of the search characters should normally equal the length
175         * of the replace characters.
176         * If the search characters is longer, then the extra search characters
177         * are deleted.
178         * If the search characters is shorter, then the extra replace characters
179         * are ignored.</p>
180         *
181         * <pre>
182         * StringUtils.replaceChars(null, *, *)           = null
183         * StringUtils.replaceChars("", *, *)             = ""
184         * StringUtils.replaceChars("abc", null, *)       = "abc"
185         * StringUtils.replaceChars("abc", "", *)         = "abc"
186         * StringUtils.replaceChars("abc", "b", null)     = "ac"
187         * StringUtils.replaceChars("abc", "b", "")       = "ac"
188         * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
189         * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
190         * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
191         * </pre>
192         *
193         * @param str  String to replace characters in, may be null
194         * @param searchChars  a set of characters to search for, may be null
195         * @param replaceChars  a set of characters to replace, may be null
196         * @return modified String, <code>null</code> if null string input
197         * @since 2.0
198         */
199        public static String replaceChars(String str, String searchChars,
200            String replaceChars)
201        {
202            if (isEmpty( str ) || isEmpty( searchChars ))
203            {
204                return str;
205            }
206            if (replaceChars == null)
207            {
208                replaceChars = "";
209            }
210            boolean modified = false;
211            StringBuffer buf = new StringBuffer( str.length() );
212            for (int i = 0; i < str.length(); i++)
213            {
214                char ch = str.charAt( i );
215                int index = searchChars.indexOf( ch );
216                if (index >= 0)
217                {
218                    modified = true;
219                    if (index < replaceChars.length())
220                    {
221                        buf.append( replaceChars.charAt( index ) );
222                    }
223                }
224                else
225                {
226                    buf.append( ch );
227                }
228            }
229            if (modified)
230            {
231                return buf.toString();
232            }
233            else
234            {
235                return str;
236            }
237        }
238    
239        /**
240         * <p>Checks if a String is empty ("") or null.</p>
241         *
242         * <pre>
243         * StringUtils.isEmpty(null)      = true
244         * StringUtils.isEmpty("")        = true
245         * StringUtils.isEmpty(" ")       = false
246         * StringUtils.isEmpty("bob")     = false
247         * StringUtils.isEmpty("  bob  ") = false
248         * </pre>
249         *
250         * <p>NOTE: This method changed in Lang version 2.0.
251         * It no longer trims the String.
252         * That functionality is available in isBlank().</p>
253         *
254         * @param str  the String to check, may be null
255         * @return <code>true</code> if the String is empty or null
256         */
257        public static boolean isEmpty(String str)
258        {
259            return str == null || str.length() == 0;
260        }
261    
262        /**
263         * Perform a series of substitutions. The substitions
264         * are performed by replacing ${variable} in the target
265         * string with the value of provided by the key "variable"
266         * in the provided hashtable.
267         *
268         * @param argStr target string
269         * @param vars name/value pairs used for substitution
270         * @param isLenient ignore failures
271         * @return String target string with replacements.
272         */
273        public static StringBuffer stringSubstitution(String argStr, Map vars, boolean isLenient)
274        {
275            StringBuffer argBuf = new StringBuffer();
276            int argStrLength = argStr.length();
277    
278            for (int cIdx = 0 ; cIdx < argStrLength;)
279            {
280                char ch = argStr.charAt(cIdx);
281                char del = ' ';
282    
283                switch (ch)
284                {
285                    case '$':
286                        StringBuffer nameBuf = new StringBuffer();
287                        del = argStr.charAt(cIdx+1);
288                        if( del == '{')
289                        {
290                            cIdx++;
291    
292                            for (++cIdx ; cIdx < argStr.length(); ++cIdx)
293                            {
294                                ch = argStr.charAt(cIdx);
295                                if (ch != '}')
296                                    nameBuf.append(ch);
297                                else
298                                    break;
299                            }
300    
301                            if (nameBuf.length() > 0)
302                            {
303                                Object value = vars.get(nameBuf.toString());
304    
305                                if (value != null)
306                                {
307                                    argBuf.append(value.toString());
308                                }
309                                else
310                                {
311                                    if (!isLenient)
312                                    {
313                                        throw new RuntimeException("No value found for : " + nameBuf );
314                                    }
315                                }
316    
317                                del = argStr.charAt(cIdx);
318    
319                                if( del != '}')
320                                {
321                                    throw new RuntimeException("Delimineter not found for : " + nameBuf );
322                                }
323                            }
324    
325                            cIdx++;
326                        }
327                        else
328                        {
329                            argBuf.append(ch);
330                            ++cIdx;
331                        }
332    
333                        break;
334    
335                    default:
336                        argBuf.append(ch);
337                        ++cIdx;
338                        break;
339                }
340            }
341    
342            return argBuf;
343        }
344    }