    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    }