001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.lang3;
018    
019    /**
020     * <p>Operations on <code>CharSet</code>s.</p>
021     *
022     * <p>This class handles <code>null</code> input gracefully.
023     * An exception will not be thrown for a <code>null</code> input.
024     * Each method documents its behaviour in more detail.</p>
025     * 
026     * <p>#ThreadSafe#</p>
027     * @see CharSet
028     * @author Apache Software Foundation
029     * @author Phil Steitz
030     * @author Gary Gregory
031     * @since 1.0
032     * @version $Id: CharSetUtils.java 918868 2010-03-04 06:22:16Z bayard $
033     */
034    public class CharSetUtils {
035    
036        /**
037         * <p>CharSetUtils instances should NOT be constructed in standard programming.
038         * Instead, the class should be used as <code>CharSetUtils.evaluateSet(null);</code>.</p>
039         *
040         * <p>This constructor is public to permit tools that require a JavaBean instance
041         * to operate.</p>
042         */
043        public CharSetUtils() {
044          super();
045        }
046    
047        // Squeeze
048        //-----------------------------------------------------------------------
049        /**
050         * <p>Squeezes any repetitions of a character that is mentioned in the
051         * supplied set.</p>
052         *
053         * <pre>
054         * CharSetUtils.squeeze(null, *)        = null
055         * CharSetUtils.squeeze("", *)          = ""
056         * CharSetUtils.squeeze(*, null)        = *
057         * CharSetUtils.squeeze(*, "")          = *
058         * CharSetUtils.squeeze("hello", "k-p") = "helo"
059         * CharSetUtils.squeeze("hello", "a-e") = "hello"
060         * </pre>
061         *
062         * @see CharSet#getInstance(java.lang.String) for set-syntax.
063         * @param str  the string to squeeze, may be null
064         * @param set  the character set to use for manipulation, may be null
065         * @return modified String, <code>null</code> if null string input
066         */
067        public static String squeeze(String str, String set) {
068            if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
069                return str;
070            }
071            String[] strs = new String[1];
072            strs[0] = set;
073            return squeeze(str, strs);
074        }
075    
076        /**
077         * <p>Squeezes any repetitions of a character that is mentioned in the
078         * supplied set.</p>
079         *
080         * <p>An example is:</p>
081         * <ul>
082         *   <li>squeeze(&quot;hello&quot;, {&quot;el&quot;}) => &quot;helo&quot;</li>
083         * </ul>
084         * 
085         * @see CharSet#getInstance(java.lang.String) for set-syntax.
086         * @param str  the string to squeeze, may be null
087         * @param set  the character set to use for manipulation, may be null
088         * @return modified String, <code>null</code> if null string input
089         */
090        public static String squeeze(String str, String[] set) {
091            if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
092                return str;
093            }
094            CharSet chars = CharSet.getInstance(set);
095            StringBuilder buffer = new StringBuilder(str.length());
096            char[] chrs = str.toCharArray();
097            int sz = chrs.length;
098            char lastChar = ' ';
099            char ch = ' ';
100            for (int i = 0; i < sz; i++) {
101                ch = chrs[i];
102                if (chars.contains(ch)) {
103                    if ((ch == lastChar) && (i != 0)) {
104                        continue;
105                    }
106                }
107                buffer.append(ch);
108                lastChar = ch;
109            }
110            return buffer.toString();
111        }
112    
113        // Count
114        //-----------------------------------------------------------------------
115        /**
116         * <p>Takes an argument in set-syntax, see evaluateSet,
117         * and returns the number of characters present in the specified string.</p>
118         *
119         * <pre>
120         * CharSetUtils.count(null, *)        = 0
121         * CharSetUtils.count("", *)          = 0
122         * CharSetUtils.count(*, null)        = 0
123         * CharSetUtils.count(*, "")          = 0
124         * CharSetUtils.count("hello", "k-p") = 3
125         * CharSetUtils.count("hello", "a-e") = 1
126         * </pre>
127         *
128         * @see CharSet#getInstance(java.lang.String) for set-syntax.
129         * @param str  String to count characters in, may be null
130         * @param set  String set of characters to count, may be null
131         * @return character count, zero if null string input
132         */
133        public static int count(String str, String set) {
134            if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
135                return 0;
136            }
137            String[] strs = new String[1];
138            strs[0] = set;
139            return count(str, strs);
140        }
141        
142        /**
143         * <p>Takes an argument in set-syntax, see evaluateSet,
144         * and returns the number of characters present in the specified string.</p>
145         *
146         * <p>An example would be:</p>
147         * <ul>
148         *  <li>count(&quot;hello&quot;, {&quot;c-f&quot;, &quot;o&quot;}) returns 2.</li>
149         * </ul>
150         *
151         * @see CharSet#getInstance(java.lang.String) for set-syntax.
152         * @param str  String to count characters in, may be null
153         * @param set  String[] set of characters to count, may be null
154         * @return character count, zero if null string input
155         */
156        public static int count(String str, String[] set) {
157            if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
158                return 0;
159            }
160            CharSet chars = CharSet.getInstance(set);
161            int count = 0;
162            char[] chrs = str.toCharArray();
163            int sz = chrs.length;
164            for(int i=0; i<sz; i++) {
165                if(chars.contains(chrs[i])) {
166                    count++;
167                }
168            }
169            return count;
170        }
171    
172        // Keep
173        //-----------------------------------------------------------------------
174        /**
175         * <p>Takes an argument in set-syntax, see evaluateSet,
176         * and keeps any of characters present in the specified string.</p>
177         *
178         * <pre>
179         * CharSetUtils.keep(null, *)        = null
180         * CharSetUtils.keep("", *)          = ""
181         * CharSetUtils.keep(*, null)        = ""
182         * CharSetUtils.keep(*, "")          = ""
183         * CharSetUtils.keep("hello", "hl")  = "hll"
184         * CharSetUtils.keep("hello", "le")  = "ell"
185         * </pre>
186         *
187         * @see CharSet#getInstance(java.lang.String) for set-syntax.
188         * @param str  String to keep characters from, may be null
189         * @param set  String set of characters to keep, may be null
190         * @return modified String, <code>null</code> if null string input
191         * @since 2.0
192         */
193        public static String keep(String str, String set) {
194            if (str == null) {
195                return null;
196            }
197            if (str.length() == 0 || StringUtils.isEmpty(set)) {
198                return "";
199            }
200            String[] strs = new String[1];
201            strs[0] = set;
202            return keep(str, strs);
203        }
204        
205        /**
206         * <p>Takes an argument in set-syntax, see evaluateSet,
207         * and keeps any of characters present in the specified string.</p>
208         *
209         * <p>An example would be:</p>
210         * <ul>
211         *  <li>keep(&quot;hello&quot;, {&quot;c-f&quot;, &quot;o&quot;})
212         *   returns &quot;eo&quot;</li>
213         * </ul>
214         *
215         * @see CharSet#getInstance(java.lang.String) for set-syntax.
216         * @param str  String to keep characters from, may be null
217         * @param set  String[] set of characters to keep, may be null
218         * @return modified String, <code>null</code> if null string input
219         * @since 2.0
220         */
221        public static String keep(String str, String[] set) {
222            if (str == null) {
223                return null;
224            }
225            if (str.length() == 0 || ArrayUtils.isEmpty(set)) {
226                return "";
227            }
228            return modify(str, set, true);
229        }
230    
231        // Delete
232        //-----------------------------------------------------------------------
233        /**
234         * <p>Takes an argument in set-syntax, see evaluateSet,
235         * and deletes any of characters present in the specified string.</p>
236         *
237         * <pre>
238         * CharSetUtils.delete(null, *)        = null
239         * CharSetUtils.delete("", *)          = ""
240         * CharSetUtils.delete(*, null)        = *
241         * CharSetUtils.delete(*, "")          = *
242         * CharSetUtils.delete("hello", "hl")  = "eo"
243         * CharSetUtils.delete("hello", "le")  = "ho"
244         * </pre>
245         *
246         * @see CharSet#getInstance(java.lang.String) for set-syntax.
247         * @param str  String to delete characters from, may be null
248         * @param set  String set of characters to delete, may be null
249         * @return modified String, <code>null</code> if null string input
250         */
251        public static String delete(String str, String set) {
252            if (StringUtils.isEmpty(str) || StringUtils.isEmpty(set)) {
253                return str;
254            }
255            String[] strs = new String[1];
256            strs[0] = set;
257            return delete(str, strs);
258        }
259        
260        /**
261         * <p>Takes an argument in set-syntax, see evaluateSet,
262         * and deletes any of characters present in the specified string.</p>
263         *
264         * <p>An example would be:</p>
265         * <ul>
266         *  <li>delete(&quot;hello&quot;, {&quot;c-f&quot;, &quot;o&quot;}) returns
267         *   &quot;hll&quot;</li>
268         * </ul>
269         *
270         * @see CharSet#getInstance(java.lang.String) for set-syntax.
271         * @param str  String to delete characters from, may be null
272         * @param set  String[] set of characters to delete, may be null
273         * @return modified String, <code>null</code> if null string input
274         */
275        public static String delete(String str, String[] set) {
276            if (StringUtils.isEmpty(str) || ArrayUtils.isEmpty(set)) {
277                return str;
278            }
279            return modify(str, set, false);
280        }
281    
282        //-----------------------------------------------------------------------
283        /**
284         * Implementation of delete and keep
285         *
286         * @param str String to modify characters within
287         * @param set String[] set of characters to modify
288         * @param expect whether to evaluate on match, or non-match
289         * @return modified String
290         */
291        private static String modify(String str, String[] set, boolean expect) {
292            CharSet chars = CharSet.getInstance(set);
293            StringBuilder buffer = new StringBuilder(str.length());
294            char[] chrs = str.toCharArray();
295            int sz = chrs.length;
296            for(int i=0; i<sz; i++) {
297                if(chars.contains(chrs[i]) == expect) {
298                    buffer.append(chrs[i]);
299                }
300            }
301            return buffer.toString();
302        }
303    
304    }