    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     * Delegates to {@link Character#valueOf(char)}.
    308     *
    309     * @param c the character to convert
    310     * @return a {@code Character} representing {@code c}.
    311     * @deprecated Use {@link Character#valueOf(char)}.
    312     */
    313    @Deprecated
    314    public static Character toCharacterObject(final char c) {
    315        return Character.valueOf(c);
    316    }
    317
    318    /**
    319     * Converts the String to a Character using the first character, returning
    320     * null for empty Strings.
    321     *
    322     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    323     * same Character object each time.</p>
    324     *
    325     * <pre>
    326     *   CharUtils.toCharacterObject(null) = null
    327     *   CharUtils.toCharacterObject("")   = null
    328     *   CharUtils.toCharacterObject("A")  = 'A'
    329     *   CharUtils.toCharacterObject("BA") = 'B'
    330     * </pre>
    331     *
    332     * @param str  the character to convert
    333     * @return the Character value of the first letter of the String
    334     */
    335    public static Character toCharacterObject(final String str) {
    336        return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
    337    }
    338
    339    /**
    340     * Converts the character to the Integer it represents, throwing an
    341     * exception if the character is not numeric.
    342     *
    343     * <p>This method converts the char '1' to the int 1 and so on.</p>
    344     *
    345     * <pre>
    346     *   CharUtils.toIntValue('3')  = 3
    347     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
    348     * </pre>
    349     *
    350     * @param ch  the character to convert
    351     * @return the int value of the character
    352     * @throws IllegalArgumentException if the character is not ASCII numeric
    353     */
    354    public static int toIntValue(final char ch) {
    355        if (!isAsciiNumeric(ch)) {
    356            throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
    357        }
    358        return ch - 48;
    359    }
    360
    361    /**
    362     * Converts the character to the Integer it represents, throwing an
    363     * exception if the character is not numeric.
    364     *
    365     * <p>This method converts the char '1' to the int 1 and so on.</p>
    366     *
    367     * <pre>
    368     *   CharUtils.toIntValue('3', -1)  = 3
    369     *   CharUtils.toIntValue('A', -1)  = -1
    370     * </pre>
    371     *
    372     * @param ch  the character to convert
    373     * @param defaultValue  the default value to use if the character is not numeric
    374     * @return the int value of the character
    375     */
    376    public static int toIntValue(final char ch, final int defaultValue) {
    377        return isAsciiNumeric(ch) ? ch - 48 : defaultValue;
    378    }
    379
    380    /**
    381     * Converts the character to the Integer it represents, throwing an
    382     * exception if the character is not numeric.
    383     *
    384     * <p>This method converts the char '1' to the int 1 and so on.</p>
    385     *
    386     * <pre>
    387     *   CharUtils.toIntValue('3')  = 3
    388     *   CharUtils.toIntValue(null) throws IllegalArgumentException
    389     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
    390     * </pre>
    391     *
    392     * @param ch  the character to convert, not null
    393     * @return the int value of the character
    394     * @throws NullPointerException if the Character is null
    395     * @throws IllegalArgumentException if the Character is not ASCII numeric
    396     */
    397    public static int toIntValue(final Character ch) {
    398        return toIntValue(toChar(ch));
    399    }
    400
    401    /**
    402     * Converts the character to the Integer it represents, throwing an
    403     * exception if the character is not numeric.
    404     *
    405     * <p>This method converts the char '1' to the int 1 and so on.</p>
    406     *
    407     * <pre>
    408     *   CharUtils.toIntValue(null, -1) = -1
    409     *   CharUtils.toIntValue('3', -1)  = 3
    410     *   CharUtils.toIntValue('A', -1)  = -1
    411     * </pre>
    412     *
    413     * @param ch  the character to convert
    414     * @param defaultValue  the default value to use if the character is not numeric
    415     * @return the int value of the character
    416     */
    417    public static int toIntValue(final Character ch, final int defaultValue) {
    418        return ch != null ? toIntValue(ch.charValue(), defaultValue) : defaultValue;
    419    }
    420
    421    /**
    422     * Converts the character to a String that contains the one character.
    423     *
    424     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    425     * same String object each time.</p>
    426     *
    427     * <pre>
    428     *   CharUtils.toString(' ')  = " "
    429     *   CharUtils.toString('A')  = "A"
    430     * </pre>
    431     *
    432     * @param ch  the character to convert
    433     * @return a String containing the one specified character
    434     */
    435    public static String toString(final char ch) {
    436        if (ch < CHAR_STRING_ARRAY.length) {
    437            return CHAR_STRING_ARRAY[ch];
    438        }
    439        return String.valueOf(ch);
    440    }
    441
    442    /**
    443     * Converts the character to a String that contains the one character.
    444     *
    445     * <p>For ASCII 7 bit characters, this uses a cache that will return the
    446     * same String object each time.</p>
    447     *
    448     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
    449     *
    450     * <pre>
    451     *   CharUtils.toString(null) = null
    452     *   CharUtils.toString(' ')  = " "
    453     *   CharUtils.toString('A')  = "A"
    454     * </pre>
    455     *
    456     * @param ch  the character to convert
    457     * @return a String containing the one specified character
    458     */
    459    public static String toString(final Character ch) {
    460        return ch != null ? toString(ch.charValue()) : null;
    461    }
    462
    463    /**
    464     * Converts the string to the Unicode format '\u0020'.
    465     *
    466     * <p>This format is the Java source code format.</p>
    467     *
    468     * <pre>
    469     *   CharUtils.unicodeEscaped(' ') = "\u0020"
    470     *   CharUtils.unicodeEscaped('A') = "\u0041"
    471     * </pre>
    472     *
    473     * @param ch  the character to convert
    474     * @return the escaped Unicode string
    475     */
    476    public static String unicodeEscaped(final char ch) {
    477        return "\\u" +
    478            HEX_DIGITS[ch >> 12 & 15] +
    479            HEX_DIGITS[ch >> 8 & 15] +
    480            HEX_DIGITS[ch >> 4 & 15] +
    481            HEX_DIGITS[ch & 15];
    482    }
    483
    484    /**
    485     * Converts the string to the Unicode format '\u0020'.
    486     *
    487     * <p>This format is the Java source code format.</p>
    488     *
    489     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
    490     *
    491     * <pre>
    492     *   CharUtils.unicodeEscaped(null) = null
    493     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
    494     *   CharUtils.unicodeEscaped('A')  = "\u0041"
    495     * </pre>
    496     *
    497     * @param ch  the character to convert, may be null
    498     * @return the escaped Unicode string, null if null input
    499     */
    500    public static String unicodeEscaped(final Character ch) {
    501        return ch != null ? unicodeEscaped(ch.charValue()) : null;
    502    }
    503
    504    /**
    505     * {@link CharUtils} instances should NOT be constructed in standard programming.
    506     * Instead, the class should be used as {@code CharUtils.toString('c');}.
    507     *
    508     * <p>This constructor is public to permit tools that require a JavaBean instance
    509     * to operate.</p>
    510     *
    511     * @deprecated TODO Make private in 4.0.
    512     */
    513    @Deprecated
    514    public CharUtils() {
    515        // empty
    516    }
    517}