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}