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