    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 */
    017package org.apache.commons.lang3;
    018
    019/**
    020 * <p>Operations on char primitives and Character objects.</p>
    021 *
    022 * <p>This class tries to handle {@code null} input gracefully.
    023 * An exception will not be thrown for a {@code null} input.
    024 * Each method documents its behavior in more detail.</p>
    025 *
    026 * <p>#ThreadSafe#</p>
    027 * @since 2.1
    028 */
    029public class CharUtils {
    030
    031    private static final String[] CHAR_STRING_ARRAY = new String[128];
    032
    033    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    034
    035    /**
    036     * Linefeed character LF ({@code '\n'}, Unicode 000a).
    037     *
    038     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    039     *      for Character and String Literals</a>
    040     * @since 2.2
    041     */
    042    public static final char LF = '\n';
    043
    044    /**
    045     * Carriage return characterf CR ('\r', Unicode 000d).
    046     *
    047     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    048     *      for Character and String Literals</a>
    049     * @since 2.2
    050     */
    051    public static final char CR = '\r';
    052
    053    /**
    054     * {@code \u0000} null control character ('\0'), abbreviated NUL.
    055     *
    056     * @since 3.6
    057     */
    058    public static final char NUL = '\0';
    059
    060    static {
    061        for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
    062            CHAR_STRING_ARRAY[c] = String.valueOf(c);
    063        }
    064    }
    065
    066    /**
    067     * <p>{@code CharUtils} instances should NOT be constructed in standard programming.
    068     * Instead, the class should be used as {@code CharUtils.toString('c');}.</p>
    069     *
    070     * <p>This constructor is public to permit tools that require a JavaBean instance
    071     * to operate.</p>
    072     */
    073    public CharUtils() {
    074    }
    075
    076    //-----------------------------------------------------------------------
    077    /**
    078     * <p>Converts the character to a Character.</p>
    079     *
    080     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    081     * same Character object each time.</p>
    082     *
    083     * <pre>
    084     *   CharUtils.toCharacterObject(' ')  = ' '
    085     *   CharUtils.toCharacterObject('A')  = 'A'
    086     * </pre>
    087     *
    088     * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
    089     * @param ch  the character to convert
    090     * @return a Character of the specified character
    091     */
    092    @Deprecated
    093    public static Character toCharacterObject(final char ch) {
    094        return Character.valueOf(ch);
    095    }
    096
    097    /**
    098     * <p>Converts the String to a Character using the first character, returning
    099     * null for empty Strings.</p>
    100     *
    101     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    102     * same Character object each time.</p>
    103     *
    104     * <pre>
    105     *   CharUtils.toCharacterObject(null) = null
    106     *   CharUtils.toCharacterObject("")   = null
    107     *   CharUtils.toCharacterObject("A")  = 'A'
    108     *   CharUtils.toCharacterObject("BA") = 'B'
    109     * </pre>
    110     *
    111     * @param str  the character to convert
    112     * @return the Character value of the first letter of the String
    113     */
    114    public static Character toCharacterObject(final String str) {
    115        if (StringUtils.isEmpty(str)) {
    116            return null;
    117        }
    118        return Character.valueOf(str.charAt(0));
    119    }
    120
    121    //-----------------------------------------------------------------------
    122    /**
    123     * <p>Converts the Character to a char throwing an exception for {@code null}.</p>
    124     *
    125     * <pre>
    126     *   CharUtils.toChar(' ')  = ' '
    127     *   CharUtils.toChar('A')  = 'A'
    128     *   CharUtils.toChar(null) throws IllegalArgumentException
    129     * </pre>
    130     *
    131     * @param ch  the character to convert
    132     * @return the char value of the Character
    133     * @throws NullPointerException if the Character is null
    134     */
    135    public static char toChar(final Character ch) {
    136        Validate.notNull(ch, "ch");
    137        return ch.charValue();
    138    }
    139
    140    /**
    141     * <p>Converts the Character to a char handling {@code null}.</p>
    142     *
    143     * <pre>
    144     *   CharUtils.toChar(null, 'X') = 'X'
    145     *   CharUtils.toChar(' ', 'X')  = ' '
    146     *   CharUtils.toChar('A', 'X')  = 'A'
    147     * </pre>
    148     *
    149     * @param ch  the character to convert
    150     * @param defaultValue  the value to use if the  Character is null
    151     * @return the char value of the Character or the default if null
    152     */
    153    public static char toChar(final Character ch, final char defaultValue) {
    154        if (ch == null) {
    155            return defaultValue;
    156        }
    157        return ch.charValue();
    158    }
    159
    160    //-----------------------------------------------------------------------
    161    /**
    162     * <p>Converts the String to a char using the first character, throwing
    163     * an exception on empty Strings.</p>
    164     *
    165     * <pre>
    166     *   CharUtils.toChar("A")  = 'A'
    167     *   CharUtils.toChar("BA") = 'B'
    168     *   CharUtils.toChar(null) throws IllegalArgumentException
    169     *   CharUtils.toChar("")   throws IllegalArgumentException
    170     * </pre>
    171     *
    172     * @param str  the character to convert
    173     * @return the char value of the first letter of the String
    174     * @throws NullPointerException if the string is null
    175     * @throws IllegalArgumentException if the String is empty
    176     */
    177    public static char toChar(final String str) {
    178        Validate.notEmpty(str, "The String must not be empty");
    179        return str.charAt(0);
    180    }
    181
    182    /**
    183     * <p>Converts the String to a char using the first character, defaulting
    184     * the value on empty Strings.</p>
    185     *
    186     * <pre>
    187     *   CharUtils.toChar(null, 'X') = 'X'
    188     *   CharUtils.toChar("", 'X')   = 'X'
    189     *   CharUtils.toChar("A", 'X')  = 'A'
    190     *   CharUtils.toChar("BA", 'X') = 'B'
    191     * </pre>
    192     *
    193     * @param str  the character to convert
    194     * @param defaultValue  the value to use if the  Character is null
    195     * @return the char value of the first letter of the String or the default if null
    196     */
    197    public static char toChar(final String str, final char defaultValue) {
    198        if (StringUtils.isEmpty(str)) {
    199            return defaultValue;
    200        }
    201        return str.charAt(0);
    202    }
    203
    204    //-----------------------------------------------------------------------
    205    /**
    206     * <p>Converts the character to the Integer it represents, throwing an
    207     * exception if the character is not numeric.</p>
    208     *
    209     * <p>This method converts the char '1' to the int 1 and so on.</p>
    210     *
    211     * <pre>
    212     *   CharUtils.toIntValue('3')  = 3
    213     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
    214     * </pre>
    215     *
    216     * @param ch  the character to convert
    217     * @return the int value of the character
    218     * @throws IllegalArgumentException if the character is not ASCII numeric
    219     */
    220    public static int toIntValue(final char ch) {
    221        if (!isAsciiNumeric(ch)) {
    222            throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
    223        }
    224        return ch - 48;
    225    }
    226
    227    /**
    228     * <p>Converts the character to the Integer it represents, throwing an
    229     * exception if the character is not numeric.</p>
    230     *
    231     * <p>This method converts the char '1' to the int 1 and so on.</p>
    232     *
    233     * <pre>
    234     *   CharUtils.toIntValue('3', -1)  = 3
    235     *   CharUtils.toIntValue('A', -1)  = -1
    236     * </pre>
    237     *
    238     * @param ch  the character to convert
    239     * @param defaultValue  the default value to use if the character is not numeric
    240     * @return the int value of the character
    241     */
    242    public static int toIntValue(final char ch, final int defaultValue) {
    243        if (!isAsciiNumeric(ch)) {
    244            return defaultValue;
    245        }
    246        return ch - 48;
    247    }
    248
    249    /**
    250     * <p>Converts the character to the Integer it represents, throwing an
    251     * exception if the character is not numeric.</p>
    252     *
    253     * <p>This method converts the char '1' to the int 1 and so on.</p>
    254     *
    255     * <pre>
    256     *   CharUtils.toIntValue('3')  = 3
    257     *   CharUtils.toIntValue(null) throws IllegalArgumentException
    258     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
    259     * </pre>
    260     *
    261     * @param ch  the character to convert, not null
    262     * @return the int value of the character
    263     * @throws NullPointerException if the Character is null
    264     * @throws IllegalArgumentException if the Character is not ASCII numeric
    265     */
    266    public static int toIntValue(final Character ch) {
    267        Validate.notNull(ch, "ch");
    268        return toIntValue(ch.charValue());
    269    }
    270
    271    /**
    272     * <p>Converts the character to the Integer it represents, throwing an
    273     * exception if the character is not numeric.</p>
    274     *
    275     * <p>This method converts the char '1' to the int 1 and so on.</p>
    276     *
    277     * <pre>
    278     *   CharUtils.toIntValue(null, -1) = -1
    279     *   CharUtils.toIntValue('3', -1)  = 3
    280     *   CharUtils.toIntValue('A', -1)  = -1
    281     * </pre>
    282     *
    283     * @param ch  the character to convert
    284     * @param defaultValue  the default value to use if the character is not numeric
    285     * @return the int value of the character
    286     */
    287    public static int toIntValue(final Character ch, final int defaultValue) {
    288        if (ch == null) {
    289            return defaultValue;
    290        }
    291        return toIntValue(ch.charValue(), defaultValue);
    292    }
    293
    294    //-----------------------------------------------------------------------
    295    /**
    296     * <p>Converts the character to a String that contains the one character.</p>
    297     *
    298     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    299     * same String object each time.</p>
    300     *
    301     * <pre>
    302     *   CharUtils.toString(' ')  = " "
    303     *   CharUtils.toString('A')  = "A"
    304     * </pre>
    305     *
    306     * @param ch  the character to convert
    307     * @return a String containing the one specified character
    308     */
    309    public static String toString(final char ch) {
    310        if (ch < 128) {
    311            return CHAR_STRING_ARRAY[ch];
    312        }
    313        return new String(new char[] {ch});
    314    }
    315
    316    /**
    317     * <p>Converts the character to a String that contains the one character.</p>
    318     *
    319     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    320     * same String object each time.</p>
    321     *
    322     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
    323     *
    324     * <pre>
    325     *   CharUtils.toString(null) = null
    326     *   CharUtils.toString(' ')  = " "
    327     *   CharUtils.toString('A')  = "A"
    328     * </pre>
    329     *
    330     * @param ch  the character to convert
    331     * @return a String containing the one specified character
    332     */
    333    public static String toString(final Character ch) {
    334        if (ch == null) {
    335            return null;
    336        }
    337        return toString(ch.charValue());
    338    }
    339
    340    //--------------------------------------------------------------------------
    341    /**
    342     * <p>Converts the string to the Unicode format '\u0020'.</p>
    343     *
    344     * <p>This format is the Java source code format.</p>
    345     *
    346     * <pre>
    347     *   CharUtils.unicodeEscaped(' ') = "\u0020"
    348     *   CharUtils.unicodeEscaped('A') = "\u0041"
    349     * </pre>
    350     *
    351     * @param ch  the character to convert
    352     * @return the escaped Unicode string
    353     */
    354    public static String unicodeEscaped(final char ch) {
    355        return "\\u" +
    356            HEX_DIGITS[(ch >> 12) & 15] +
    357            HEX_DIGITS[(ch >> 8) & 15] +
    358            HEX_DIGITS[(ch >> 4) & 15] +
    359            HEX_DIGITS[(ch) & 15];
    360    }
    361
    362    /**
    363     * <p>Converts the string to the Unicode format '\u0020'.</p>
    364     *
    365     * <p>This format is the Java source code format.</p>
    366     *
    367     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
    368     *
    369     * <pre>
    370     *   CharUtils.unicodeEscaped(null) = null
    371     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
    372     *   CharUtils.unicodeEscaped('A')  = "\u0041"
    373     * </pre>
    374     *
    375     * @param ch  the character to convert, may be null
    376     * @return the escaped Unicode string, null if null input
    377     */
    378    public static String unicodeEscaped(final Character ch) {
    379        if (ch == null) {
    380            return null;
    381        }
    382        return unicodeEscaped(ch.charValue());
    383    }
    384
    385    //--------------------------------------------------------------------------
    386    /**
    387     * <p>Checks whether the character is ASCII 7 bit.</p>
    388     *
    389     * <pre>
    390     *   CharUtils.isAscii('a')  = true
    391     *   CharUtils.isAscii('A')  = true
    392     *   CharUtils.isAscii('3')  = true
    393     *   CharUtils.isAscii('-')  = true
    394     *   CharUtils.isAscii('\n') = true
    395     *   CharUtils.isAscii('&copy;') = false
    396     * </pre>
    397     *
    398     * @param ch  the character to check
    399     * @return true if less than 128
    400     */
    401    public static boolean isAscii(final char ch) {
    402        return ch < 128;
    403    }
    404
    405    /**
    406     * <p>Checks whether the character is ASCII 7 bit printable.</p>
    407     *
    408     * <pre>
    409     *   CharUtils.isAsciiPrintable('a')  = true
    410     *   CharUtils.isAsciiPrintable('A')  = true
    411     *   CharUtils.isAsciiPrintable('3')  = true
    412     *   CharUtils.isAsciiPrintable('-')  = true
    413     *   CharUtils.isAsciiPrintable('\n') = false
    414     *   CharUtils.isAsciiPrintable('&copy;') = false
    415     * </pre>
    416     *
    417     * @param ch  the character to check
    418     * @return true if between 32 and 126 inclusive
    419     */
    420    public static boolean isAsciiPrintable(final char ch) {
    421        return ch >= 32 && ch < 127;
    422    }
    423
    424    /**
    425     * <p>Checks whether the character is ASCII 7 bit control.</p>
    426     *
    427     * <pre>
    428     *   CharUtils.isAsciiControl('a')  = false
    429     *   CharUtils.isAsciiControl('A')  = false
    430     *   CharUtils.isAsciiControl('3')  = false
    431     *   CharUtils.isAsciiControl('-')  = false
    432     *   CharUtils.isAsciiControl('\n') = true
    433     *   CharUtils.isAsciiControl('&copy;') = false
    434     * </pre>
    435     *
    436     * @param ch  the character to check
    437     * @return true if less than 32 or equals 127
    438     */
    439    public static boolean isAsciiControl(final char ch) {
    440        return ch < 32 || ch == 127;
    441    }
    442
    443    /**
    444     * <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
    445     *
    446     * <pre>
    447     *   CharUtils.isAsciiAlpha('a')  = true
    448     *   CharUtils.isAsciiAlpha('A')  = true
    449     *   CharUtils.isAsciiAlpha('3')  = false
    450     *   CharUtils.isAsciiAlpha('-')  = false
    451     *   CharUtils.isAsciiAlpha('\n') = false
    452     *   CharUtils.isAsciiAlpha('&copy;') = false
    453     * </pre>
    454     *
    455     * @param ch  the character to check
    456     * @return true if between 65 and 90 or 97 and 122 inclusive
    457     */
    458    public static boolean isAsciiAlpha(final char ch) {
    459        return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
    460    }
    461
    462    /**
    463     * <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
    464     *
    465     * <pre>
    466     *   CharUtils.isAsciiAlphaUpper('a')  = false
    467     *   CharUtils.isAsciiAlphaUpper('A')  = true
    468     *   CharUtils.isAsciiAlphaUpper('3')  = false
    469     *   CharUtils.isAsciiAlphaUpper('-')  = false
    470     *   CharUtils.isAsciiAlphaUpper('\n') = false
    471     *   CharUtils.isAsciiAlphaUpper('&copy;') = false
    472     * </pre>
    473     *
    474     * @param ch  the character to check
    475     * @return true if between 65 and 90 inclusive
    476     */
    477    public static boolean isAsciiAlphaUpper(final char ch) {
    478        return ch >= 'A' && ch <= 'Z';
    479    }
    480
    481    /**
    482     * <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
    483     *
    484     * <pre>
    485     *   CharUtils.isAsciiAlphaLower('a')  = true
    486     *   CharUtils.isAsciiAlphaLower('A')  = false
    487     *   CharUtils.isAsciiAlphaLower('3')  = false
    488     *   CharUtils.isAsciiAlphaLower('-')  = false
    489     *   CharUtils.isAsciiAlphaLower('\n') = false
    490     *   CharUtils.isAsciiAlphaLower('&copy;') = false
    491     * </pre>
    492     *
    493     * @param ch  the character to check
    494     * @return true if between 97 and 122 inclusive
    495     */
    496    public static boolean isAsciiAlphaLower(final char ch) {
    497        return ch >= 'a' && ch <= 'z';
    498    }
    499
    500    /**
    501     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
    502     *
    503     * <pre>
    504     *   CharUtils.isAsciiNumeric('a')  = false
    505     *   CharUtils.isAsciiNumeric('A')  = false
    506     *   CharUtils.isAsciiNumeric('3')  = true
    507     *   CharUtils.isAsciiNumeric('-')  = false
    508     *   CharUtils.isAsciiNumeric('\n') = false
    509     *   CharUtils.isAsciiNumeric('&copy;') = false
    510     * </pre>
    511     *
    512     * @param ch  the character to check
    513     * @return true if between 48 and 57 inclusive
    514     */
    515    public static boolean isAsciiNumeric(final char ch) {
    516        return ch >= '0' && ch <= '9';
    517    }
    518
    519    /**
    520     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
    521     *
    522     * <pre>
    523     *   CharUtils.isAsciiAlphanumeric('a')  = true
    524     *   CharUtils.isAsciiAlphanumeric('A')  = true
    525     *   CharUtils.isAsciiAlphanumeric('3')  = true
    526     *   CharUtils.isAsciiAlphanumeric('-')  = false
    527     *   CharUtils.isAsciiAlphanumeric('\n') = false
    528     *   CharUtils.isAsciiAlphanumeric('&copy;') = false
    529     * </pre>
    530     *
    531     * @param ch  the character to check
    532     * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
    533     */
    534    public static boolean isAsciiAlphanumeric(final char ch) {
    535        return isAsciiAlpha(ch) || isAsciiNumeric(ch);
    536    }
    537
    538    /**
    539     * <p>Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.</p>
    540     *
    541     * @param x the first {@code char} to compare
    542     * @param y the second {@code char} to compare
    543     * @return the value {@code 0} if {@code x == y};
    544     *         a value less than {@code 0} if {@code x < y}; and
    545     *         a value greater than {@code 0} if {@code x > y}
    546     * @since 3.4
    547     */
    548    public static int compare(final char x, final char y) {
    549        return x-y;
    550    }
    551}