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