View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3;
18  
19  import java.util.Objects;
20  
21  /**
22   * Operations on char primitives and Character objects.
23   *
24   * <p>This class tries to handle {@code null} input gracefully.
25   * An exception will not be thrown for a {@code null} input.
26   * Each method documents its behavior in more detail.</p>
27   *
28   * <p>#ThreadSafe#</p>
29   * @since 2.1
30   */
31  public class CharUtils {
32  
33      private static final String[] CHAR_STRING_ARRAY = new String[128];
34  
35      private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
36  
37      /**
38       * Linefeed character LF ({@code '\n'}, Unicode 000a).
39       *
40       * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
41       *      for Character and String Literals</a>
42       * @since 2.2
43       */
44      public static final char LF = '\n';
45  
46      /**
47       * Carriage return character CR ('\r', Unicode 000d).
48       *
49       * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
50       *      for Character and String Literals</a>
51       * @since 2.2
52       */
53      public static final char CR = '\r';
54  
55      /**
56       * {@code \u0000} null control character ('\0'), abbreviated NUL.
57       *
58       * @since 3.6
59       */
60      public static final char NUL = '\0';
61  
62      static {
63          ArrayUtils.setAll(CHAR_STRING_ARRAY, i -> String.valueOf((char) i));
64      }
65  
66      /**
67       * Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
68       *
69       * @param x the first {@code char} to compare
70       * @param y the second {@code char} to compare
71       * @return the value {@code 0} if {@code x == y};
72       *         a value less than {@code 0} if {@code x < y}; and
73       *         a value greater than {@code 0} if {@code x > y}
74       * @since 3.4
75       */
76      public static int compare(final char x, final char y) {
77          return x - y;
78      }
79  
80      /**
81       * Checks whether the character is ASCII 7 bit.
82       *
83       * <pre>
84       *   CharUtils.isAscii('a')  = true
85       *   CharUtils.isAscii('A')  = true
86       *   CharUtils.isAscii('3')  = true
87       *   CharUtils.isAscii('-')  = true
88       *   CharUtils.isAscii('\n') = true
89       *   CharUtils.isAscii('&copy;') = false
90       * </pre>
91       *
92       * @param ch  the character to check
93       * @return true if less than 128
94       */
95      public static boolean isAscii(final char ch) {
96          return ch < 128;
97      }
98  
99      /**
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 }