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