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 * https://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>
25 * This class tries to handle {@code null} input gracefully.
26 * An exception will not be thrown for a {@code null} input.
27 * Each method documents its behavior in more detail.
28 * </p>
29 *
30 * <p>
31 * #ThreadSafe#
32 * </p>
33 *
34 * @since 2.1
35 */
36 public class CharUtils {
37
38 private static final String[] CHAR_STRING_ARRAY = ArrayUtils.setAll(new String[128], i -> String.valueOf((char) i));
39
40 private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
41
42 /**
43 * Linefeed character LF ({@code '\n'}, Unicode 000a).
44 *
45 * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
46 * for Character and String Literals</a>
47 * @since 2.2
48 */
49 public static final char LF = '\n';
50
51 /**
52 * Carriage return character CR ('\r', Unicode 000d).
53 *
54 * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
55 * for Character and String Literals</a>
56 * @since 2.2
57 */
58 public static final char CR = '\r';
59
60 /**
61 * {@code \u0000} null control character ('\0'), abbreviated NUL.
62 *
63 * @since 3.6
64 */
65 public static final char NUL = '\0';
66
67 /**
68 * Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
69 *
70 * @param x The first {@code char} to compare
71 * @param y The second {@code char} to compare
72 * @return The value {@code 0} if {@code x == y};
73 * a value less than {@code 0} if {@code x < y}; and
74 * a value greater than {@code 0} if {@code x > y}
75 * @since 3.4
76 */
77 public static int compare(final char x, final char y) {
78 return x - y;
79 }
80
81 /**
82 * Tests whether the character is ASCII 7 bit.
83 *
84 * <pre>
85 * CharUtils.isAscii('a') = true
86 * CharUtils.isAscii('A') = true
87 * CharUtils.isAscii('3') = true
88 * CharUtils.isAscii('-') = true
89 * CharUtils.isAscii('\n') = true
90 * CharUtils.isAscii('©') = false
91 * </pre>
92 *
93 * @param ch The character to check
94 * @return true if less than 128
95 */
96 public static boolean isAscii(final char ch) {
97 return ch < 128;
98 }
99
100 /**
101 * Tests whether the character is ASCII 7 bit alphabetic.
102 *
103 * <pre>
104 * CharUtils.isAsciiAlpha('a') = true
105 * CharUtils.isAsciiAlpha('A') = true
106 * CharUtils.isAsciiAlpha('3') = false
107 * CharUtils.isAsciiAlpha('-') = false
108 * CharUtils.isAsciiAlpha('\n') = false
109 * CharUtils.isAsciiAlpha('©') = false
110 * </pre>
111 *
112 * @param ch The character to check
113 * @return true if between 65 and 90 or 97 and 122 inclusive
114 */
115 public static boolean isAsciiAlpha(final char ch) {
116 return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
117 }
118
119 /**
120 * Tests whether the character is ASCII 7 bit alphabetic lower case.
121 *
122 * <pre>
123 * CharUtils.isAsciiAlphaLower('a') = true
124 * CharUtils.isAsciiAlphaLower('A') = false
125 * CharUtils.isAsciiAlphaLower('3') = false
126 * CharUtils.isAsciiAlphaLower('-') = false
127 * CharUtils.isAsciiAlphaLower('\n') = false
128 * CharUtils.isAsciiAlphaLower('©') = false
129 * </pre>
130 *
131 * @param ch The character to check
132 * @return true if between 97 and 122 inclusive
133 */
134 public static boolean isAsciiAlphaLower(final char ch) {
135 return ch >= 'a' && ch <= 'z';
136 }
137
138 /**
139 * Tests whether the character is ASCII 7 bit alphanumeric character.
140 *
141 * <pre>
142 * CharUtils.isAsciiAlphanumeric('a') = true
143 * CharUtils.isAsciiAlphanumeric('A') = true
144 * CharUtils.isAsciiAlphanumeric('3') = true
145 * CharUtils.isAsciiAlphanumeric('-') = false
146 * CharUtils.isAsciiAlphanumeric('\n') = false
147 * CharUtils.isAsciiAlphanumeric('©') = false
148 * </pre>
149 *
150 * @param ch The character to check
151 * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
152 */
153 public static boolean isAsciiAlphanumeric(final char ch) {
154 return isAsciiAlpha(ch) || isAsciiNumeric(ch);
155 }
156
157 /**
158 * Tests whether the character is ASCII 7 bit alphabetic upper case.
159 *
160 * <pre>
161 * CharUtils.isAsciiAlphaUpper('a') = false
162 * CharUtils.isAsciiAlphaUpper('A') = true
163 * CharUtils.isAsciiAlphaUpper('3') = false
164 * CharUtils.isAsciiAlphaUpper('-') = false
165 * CharUtils.isAsciiAlphaUpper('\n') = false
166 * CharUtils.isAsciiAlphaUpper('©') = false
167 * </pre>
168 *
169 * @param ch The character to check
170 * @return true if between 65 and 90 inclusive
171 */
172 public static boolean isAsciiAlphaUpper(final char ch) {
173 return ch >= 'A' && ch <= 'Z';
174 }
175
176 /**
177 * Tests whether the character is ASCII 7 bit control.
178 *
179 * <pre>
180 * CharUtils.isAsciiControl('a') = false
181 * CharUtils.isAsciiControl('A') = false
182 * CharUtils.isAsciiControl('3') = false
183 * CharUtils.isAsciiControl('-') = false
184 * CharUtils.isAsciiControl('\n') = true
185 * CharUtils.isAsciiControl('©') = false
186 * </pre>
187 *
188 * @param ch The character to check
189 * @return true if less than 32 or equals 127
190 */
191 public static boolean isAsciiControl(final char ch) {
192 return ch < 32 || ch == 127;
193 }
194
195 /**
196 * Tests whether the character is ASCII 7 bit numeric.
197 *
198 * <pre>
199 * CharUtils.isAsciiNumeric('a') = false
200 * CharUtils.isAsciiNumeric('A') = false
201 * CharUtils.isAsciiNumeric('3') = true
202 * CharUtils.isAsciiNumeric('-') = false
203 * CharUtils.isAsciiNumeric('\n') = false
204 * CharUtils.isAsciiNumeric('©') = false
205 * </pre>
206 *
207 * @param ch The character to check
208 * @return true if between 48 and 57 inclusive
209 */
210 public static boolean isAsciiNumeric(final char ch) {
211 return ch >= '0' && ch <= '9';
212 }
213
214 /**
215 * Tests whether the character is ASCII 7 bit numeric.
216 *
217 * <pre>
218 * CharUtils.isAsciiNumeric('a') = false
219 * CharUtils.isAsciiNumeric('A') = false
220 * CharUtils.isAsciiNumeric('3') = true
221 * CharUtils.isAsciiNumeric('-') = false
222 * CharUtils.isAsciiNumeric('\n') = false
223 * CharUtils.isAsciiNumeric('©') = false
224 * </pre>
225 *
226 * @param ch The code point to check.
227 * @return true if between 48 and 57 inclusive.
228 * @since 3.21.0
229 */
230 public static boolean isAsciiNumeric(final int ch) {
231 return ch >= '0' && ch <= '9';
232 }
233
234 /**
235 * Tests whether the character is ASCII 7 bit printable.
236 *
237 * <pre>
238 * CharUtils.isAsciiPrintable('a') = true
239 * CharUtils.isAsciiPrintable('A') = true
240 * CharUtils.isAsciiPrintable('3') = true
241 * CharUtils.isAsciiPrintable('-') = true
242 * CharUtils.isAsciiPrintable('\n') = false
243 * CharUtils.isAsciiPrintable('©') = false
244 * </pre>
245 *
246 * @param ch The character to check
247 * @return true if between 32 and 126 inclusive
248 */
249 public static boolean isAsciiPrintable(final char ch) {
250 return ch >= 32 && ch < 127;
251 }
252
253 /**
254 * Tests whether a character is a hexadecimal character.
255 *
256 * <pre>
257 * CharUtils.isHex('0') = true
258 * CharUtils.isHex('3') = true
259 * CharUtils.isHex('9') = true
260 * CharUtils.isHex('a') = true
261 * CharUtils.isHex('f') = true
262 * CharUtils.isHex('g') = false
263 * CharUtils.isHex('A') = true
264 * CharUtils.isHex('F') = true
265 * CharUtils.isHex('G') = false
266 * CharUtils.isHex('#') = false
267 * CharUtils.isHex('-') = false
268 * CharUtils.isHex('\n') = false
269 * CharUtils.isHex('©') = false
270 * </pre>
271 *
272 * @param ch The character to test.
273 * @return true if character is a hexadecimal character.
274 * @since 3.18.0
275 */
276 public static boolean isHex(final char ch) {
277 return isAsciiNumeric(ch) || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
278 }
279
280 /**
281 * Tests whether a character is a hexadecimal character.
282 *
283 * <pre>
284 * CharUtils.isHex('0') = true
285 * CharUtils.isHex('3') = true
286 * CharUtils.isHex('9') = true
287 * CharUtils.isHex('a') = true
288 * CharUtils.isHex('f') = true
289 * CharUtils.isHex('g') = false
290 * CharUtils.isHex('A') = true
291 * CharUtils.isHex('F') = true
292 * CharUtils.isHex('G') = false
293 * CharUtils.isHex('#') = false
294 * CharUtils.isHex('-') = false
295 * CharUtils.isHex('\n') = false
296 * CharUtils.isHex('©') = false
297 * </pre>
298 *
299 * @param ch The code point to test.
300 * @return true if character is a hexadecimal character.
301 * @since 3.21.0
302 */
303 public static boolean isHex(final int ch) {
304 return isAsciiNumeric(ch) || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
305 }
306
307 /**
308 * Tests if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
309 *
310 * @param ch The byte to check.
311 * @return true if the given char is the character representation of one of the digits from 0 to 7.
312 * @since 3.21.0
313 */
314 public static boolean isOctal(final byte ch) {
315 return ch >= '0' && ch <= '7';
316 }
317
318 /**
319 * Tests if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
320 *
321 * @param ch The char to check.
322 * @return true if the given char is the character representation of one of the digits from 0 to 7.
323 * @since 3.18.0
324 */
325 public static boolean isOctal(final char ch) {
326 return ch >= '0' && ch <= '7';
327 }
328
329 /**
330 * Converts the Character to a char throwing an exception for {@code null}.
331 *
332 * <pre>
333 * CharUtils.toChar(' ') = ' '
334 * CharUtils.toChar('A') = 'A'
335 * CharUtils.toChar(null) throws NullPointerException
336 * </pre>
337 *
338 * @param ch The character to convert
339 * @return The char value of the Character
340 * @throws NullPointerException Thrown if the Character is null.
341 */
342 public static char toChar(final Character ch) {
343 return Objects.requireNonNull(ch, "ch").charValue();
344 }
345
346 /**
347 * Converts the Character to a char handling {@code null}.
348 *
349 * <pre>
350 * CharUtils.toChar(null, 'X') = 'X'
351 * CharUtils.toChar(' ', 'X') = ' '
352 * CharUtils.toChar('A', 'X') = 'A'
353 * </pre>
354 *
355 * @param ch The character to convert
356 * @param defaultValue The value to use if the Character is null
357 * @return The char value of the Character or the default if null
358 */
359 public static char toChar(final Character ch, final char defaultValue) {
360 return ch != null ? ch.charValue() : defaultValue;
361 }
362
363 /**
364 * Converts the String to a char using the first character, throwing
365 * an exception on empty Strings.
366 *
367 * <pre>
368 * CharUtils.toChar("A") = 'A'
369 * CharUtils.toChar("BA") = 'B'
370 * CharUtils.toChar(null) throws NullPointerException
371 * CharUtils.toChar("") throws IllegalArgumentException
372 * </pre>
373 *
374 * @param str The character to convert
375 * @return The char value of the first letter of the String
376 * @throws NullPointerException Thrown if the string is null.
377 * @throws IllegalArgumentException Thrown if the String is empty.
378 */
379 public static char toChar(final String str) {
380 Validate.notEmpty(str, "The String must not be empty");
381 return str.charAt(0);
382 }
383
384 /**
385 * Converts the String to a char using the first character, defaulting
386 * the value on empty Strings.
387 *
388 * <pre>
389 * CharUtils.toChar(null, 'X') = 'X'
390 * CharUtils.toChar("", 'X') = 'X'
391 * CharUtils.toChar("A", 'X') = 'A'
392 * CharUtils.toChar("BA", 'X') = 'B'
393 * </pre>
394 *
395 * @param str The character to convert
396 * @param defaultValue The value to use if the Character is null
397 * @return The char value of the first letter of the String or the default if null
398 */
399 public static char toChar(final String str, final char defaultValue) {
400 return StringUtils.isEmpty(str) ? defaultValue : str.charAt(0);
401 }
402
403 /**
404 * Delegates to {@link Character#valueOf(char)}.
405 *
406 * @param c The character to convert
407 * @return A {@code Character} representing {@code c}.
408 * @deprecated Use {@link Character#valueOf(char)}.
409 */
410 @Deprecated
411 public static Character toCharacterObject(final char c) {
412 return Character.valueOf(c);
413 }
414
415 /**
416 * Converts the String to a Character using the first character, returning
417 * null for empty Strings.
418 *
419 * <p>
420 * For ASCII 7 bit characters, this uses a cache that will return the
421 * same Character object each time.
422 * </p>
423 *
424 * <pre>
425 * CharUtils.toCharacterObject(null) = null
426 * CharUtils.toCharacterObject("") = null
427 * CharUtils.toCharacterObject("A") = 'A'
428 * CharUtils.toCharacterObject("BA") = 'B'
429 * </pre>
430 *
431 * @param str The character to convert
432 * @return The Character value of the first letter of the String
433 */
434 public static Character toCharacterObject(final String str) {
435 return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
436 }
437
438 /**
439 * Converts the character to the Integer it represents, throwing an
440 * exception if the character is not numeric.
441 *
442 * <p>
443 * This method converts the char '1' to the int 1 and so on.
444 * </p>
445 *
446 * <pre>
447 * CharUtils.toIntValue('3') = 3
448 * CharUtils.toIntValue('A') throws IllegalArgumentException
449 * </pre>
450 *
451 * @param ch The character to convert
452 * @return The int value of the character
453 * @throws IllegalArgumentException Thrown if the character is not ASCII numeric.
454 */
455 public static int toIntValue(final char ch) {
456 if (!isAsciiNumeric(ch)) {
457 throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
458 }
459 return ch - 48;
460 }
461
462 /**
463 * Converts the character to the Integer it represents, throwing an
464 * exception if the character is not numeric.
465 *
466 * <p>
467 * This method converts the char '1' to the int 1 and so on.
468 * </p>
469 *
470 * <pre>
471 * CharUtils.toIntValue('3', -1) = 3
472 * CharUtils.toIntValue('A', -1) = -1
473 * </pre>
474 *
475 * @param ch The character to convert
476 * @param defaultValue The default value to use if the character is not numeric
477 * @return The int value of the character
478 */
479 public static int toIntValue(final char ch, final int defaultValue) {
480 return isAsciiNumeric(ch) ? ch - 48 : defaultValue;
481 }
482
483 /**
484 * Converts the character to the Integer it represents, throwing an
485 * exception if the character is not numeric.
486 *
487 * <p>
488 * This method converts the char '1' to the int 1 and so on.
489 * </p>
490 *
491 * <pre>
492 * CharUtils.toIntValue('3') = 3
493 * CharUtils.toIntValue(null) throws NullPointerException
494 * CharUtils.toIntValue('A') throws IllegalArgumentException
495 * </pre>
496 *
497 * @param ch The character to convert, not null
498 * @return The int value of the character
499 * @throws NullPointerException Thrown if the Character is null.
500 * @throws IllegalArgumentException Thrown if the Character is not ASCII numeric.
501 */
502 public static int toIntValue(final Character ch) {
503 return toIntValue(toChar(ch));
504 }
505
506 /**
507 * Converts the character to the Integer it represents, throwing an
508 * exception if the character is not numeric.
509 *
510 * <p>
511 * This method converts the char '1' to the int 1 and so on.
512 * </p>
513 *
514 * <pre>
515 * CharUtils.toIntValue(null, -1) = -1
516 * CharUtils.toIntValue('3', -1) = 3
517 * CharUtils.toIntValue('A', -1) = -1
518 * </pre>
519 *
520 * @param ch The character to convert
521 * @param defaultValue The default value to use if the character is not numeric
522 * @return The int value of the character
523 */
524 public static int toIntValue(final Character ch, final int defaultValue) {
525 return ch != null ? toIntValue(ch.charValue(), defaultValue) : defaultValue;
526 }
527
528 /**
529 * Converts the character to a String that contains the one character.
530 *
531 * <p>
532 * For ASCII 7 bit characters, this uses a cache that will return the
533 * same String object each time.
534 * </p>
535 *
536 * <pre>
537 * CharUtils.toString(' ') = " "
538 * CharUtils.toString('A') = "A"
539 * </pre>
540 *
541 * @param ch The character to convert
542 * @return A String containing the one specified character
543 */
544 public static String toString(final char ch) {
545 if (ch < CHAR_STRING_ARRAY.length) {
546 return CHAR_STRING_ARRAY[ch];
547 }
548 return String.valueOf(ch);
549 }
550
551 /**
552 * Converts the character to a String that contains the one character.
553 *
554 * <p>
555 * For ASCII 7 bit characters, this uses a cache that will return the
556 * same String object each time.
557 * </p>
558 *
559 * <p>
560 * If {@code null} is passed in, {@code null} will be returned.
561 * </p>
562 *
563 * <pre>
564 * CharUtils.toString(null) = null
565 * CharUtils.toString(' ') = " "
566 * CharUtils.toString('A') = "A"
567 * </pre>
568 *
569 * @param ch The character to convert
570 * @return A String containing the one specified character
571 */
572 public static String toString(final Character ch) {
573 return ch != null ? toString(ch.charValue()) : null;
574 }
575
576 /**
577 * Converts the string to the Unicode format '\u0020'.
578 *
579 * <p>
580 * This format is the Java source code format.
581 * </p>
582 *
583 * <pre>
584 * CharUtils.unicodeEscaped(' ') = "\u0020"
585 * CharUtils.unicodeEscaped('A') = "\u0041"
586 * </pre>
587 *
588 * @param ch The character to convert
589 * @return The escaped Unicode string
590 */
591 public static String unicodeEscaped(final char ch) {
592 return "\\u" +
593 HEX_DIGITS[ch >> 12 & 15] +
594 HEX_DIGITS[ch >> 8 & 15] +
595 HEX_DIGITS[ch >> 4 & 15] +
596 HEX_DIGITS[ch & 15];
597 }
598
599 /**
600 * Converts the string to the Unicode format '\u0020'.
601 *
602 * <p>
603 * This format is the Java source code format.
604 * </p>
605 *
606 * <p>
607 * If {@code null} is passed in, {@code null} will be returned.
608 * </p>
609 *
610 * <pre>
611 * CharUtils.unicodeEscaped(null) = null
612 * CharUtils.unicodeEscaped(' ') = "\u0020"
613 * CharUtils.unicodeEscaped('A') = "\u0041"
614 * </pre>
615 *
616 * @param ch The character to convert, may be null
617 * @return The escaped Unicode string, null if null input
618 */
619 public static String unicodeEscaped(final Character ch) {
620 return ch != null ? unicodeEscaped(ch.charValue()) : null;
621 }
622
623 /**
624 * {@link CharUtils} instances should NOT be constructed in standard programming.
625 * Instead, the class should be used as {@code CharUtils.toString('c');}.
626 *
627 * <p>
628 * This constructor is public to permit tools that require a JavaBean instance
629 * to operate.
630 * </p>
631 *
632 * @deprecated TODO Make private in 4.0.
633 */
634 @Deprecated
635 public CharUtils() {
636 // empty
637 }
638 }