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}