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