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
019/**
020 * <p>Operations on char primitives and Character objects.</p>
021 *
022 * <p>This class tries to handle {@code null} input gracefully.
023 * An exception will not be thrown for a {@code null} input.
024 * Each method documents its behavior in more detail.</p>
025 *
026 * <p>#ThreadSafe#</p>
027 * @since 2.1
028 */
029public class CharUtils {
030
031    private static final String[] CHAR_STRING_ARRAY = new String[128];
032
033    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
034
035    /**
036     * Linefeed character LF ({@code '\n'}, Unicode 000a).
037     *
038     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
039     *      for Character and String Literals</a>
040     * @since 2.2
041     */
042    public static final char LF = '\n';
043
044    /**
045     * Carriage return characterf CR ('\r', Unicode 000d).
046     *
047     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
048     *      for Character and String Literals</a>
049     * @since 2.2
050     */
051    public static final char CR = '\r';
052
053    /**
054     * {@code \u0000} null control character ('\0'), abbreviated NUL.
055     *
056     * @since 3.6
057     */
058    public static final char NUL = '\0';
059
060    static {
061        for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
062            CHAR_STRING_ARRAY[c] = String.valueOf(c);
063        }
064    }
065
066    /**
067     * <p>{@code CharUtils} instances should NOT be constructed in standard programming.
068     * Instead, the class should be used as {@code CharUtils.toString('c');}.</p>
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    /**
078     * <p>Converts the character to a Character.</p>
079     *
080     * <p>For ASCII 7 bit characters, this uses a cache that will return the
081     * same Character object each time.</p>
082     *
083     * <pre>
084     *   CharUtils.toCharacterObject(' ')  = ' '
085     *   CharUtils.toCharacterObject('A')  = 'A'
086     * </pre>
087     *
088     * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
089     * @param ch  the character to convert
090     * @return a Character of the specified character
091     */
092    @Deprecated
093    public static Character toCharacterObject(final char ch) {
094        return Character.valueOf(ch);
095    }
096
097    /**
098     * <p>Converts the String to a Character using the first character, returning
099     * null for empty Strings.</p>
100     *
101     * <p>For ASCII 7 bit characters, this uses a cache that will return the
102     * same Character object each time.</p>
103     *
104     * <pre>
105     *   CharUtils.toCharacterObject(null) = null
106     *   CharUtils.toCharacterObject("")   = null
107     *   CharUtils.toCharacterObject("A")  = 'A'
108     *   CharUtils.toCharacterObject("BA") = 'B'
109     * </pre>
110     *
111     * @param str  the character to convert
112     * @return the Character value of the first letter of the String
113     */
114    public static Character toCharacterObject(final String str) {
115        if (StringUtils.isEmpty(str)) {
116            return null;
117        }
118        return Character.valueOf(str.charAt(0));
119    }
120
121    //-----------------------------------------------------------------------
122    /**
123     * <p>Converts the Character to a char throwing an exception for {@code null}.</p>
124     *
125     * <pre>
126     *   CharUtils.toChar(' ')  = ' '
127     *   CharUtils.toChar('A')  = 'A'
128     *   CharUtils.toChar(null) throws IllegalArgumentException
129     * </pre>
130     *
131     * @param ch  the character to convert
132     * @return the char value of the Character
133     * @throws NullPointerException if the Character is null
134     */
135    public static char toChar(final Character ch) {
136        Validate.notNull(ch, "ch");
137        return ch.charValue();
138    }
139
140    /**
141     * <p>Converts the Character to a char handling {@code null}.</p>
142     *
143     * <pre>
144     *   CharUtils.toChar(null, 'X') = 'X'
145     *   CharUtils.toChar(' ', 'X')  = ' '
146     *   CharUtils.toChar('A', 'X')  = 'A'
147     * </pre>
148     *
149     * @param ch  the character to convert
150     * @param defaultValue  the value to use if the  Character is null
151     * @return the char value of the Character or the default if null
152     */
153    public static char toChar(final Character ch, final char defaultValue) {
154        if (ch == null) {
155            return defaultValue;
156        }
157        return ch.charValue();
158    }
159
160    //-----------------------------------------------------------------------
161    /**
162     * <p>Converts the String to a char using the first character, throwing
163     * an exception on empty Strings.</p>
164     *
165     * <pre>
166     *   CharUtils.toChar("A")  = 'A'
167     *   CharUtils.toChar("BA") = 'B'
168     *   CharUtils.toChar(null) throws IllegalArgumentException
169     *   CharUtils.toChar("")   throws IllegalArgumentException
170     * </pre>
171     *
172     * @param str  the character to convert
173     * @return the char value of the first letter of the String
174     * @throws NullPointerException if the string is null
175     * @throws IllegalArgumentException if the String is empty
176     */
177    public static char toChar(final String str) {
178        Validate.notEmpty(str, "The String must not be empty");
179        return str.charAt(0);
180    }
181
182    /**
183     * <p>Converts the String to a char using the first character, defaulting
184     * the value on empty Strings.</p>
185     *
186     * <pre>
187     *   CharUtils.toChar(null, 'X') = 'X'
188     *   CharUtils.toChar("", 'X')   = 'X'
189     *   CharUtils.toChar("A", 'X')  = 'A'
190     *   CharUtils.toChar("BA", 'X') = 'B'
191     * </pre>
192     *
193     * @param str  the character to convert
194     * @param defaultValue  the value to use if the  Character is null
195     * @return the char value of the first letter of the String or the default if null
196     */
197    public static char toChar(final String str, final char defaultValue) {
198        if (StringUtils.isEmpty(str)) {
199            return defaultValue;
200        }
201        return str.charAt(0);
202    }
203
204    //-----------------------------------------------------------------------
205    /**
206     * <p>Converts the character to the Integer it represents, throwing an
207     * exception if the character is not numeric.</p>
208     *
209     * <p>This method converts the char '1' to the int 1 and so on.</p>
210     *
211     * <pre>
212     *   CharUtils.toIntValue('3')  = 3
213     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
214     * </pre>
215     *
216     * @param ch  the character to convert
217     * @return the int value of the character
218     * @throws IllegalArgumentException if the character is not ASCII numeric
219     */
220    public static int toIntValue(final char ch) {
221        if (!isAsciiNumeric(ch)) {
222            throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
223        }
224        return ch - 48;
225    }
226
227    /**
228     * <p>Converts the character to the Integer it represents, throwing an
229     * exception if the character is not numeric.</p>
230     *
231     * <p>This method converts the char '1' to the int 1 and so on.</p>
232     *
233     * <pre>
234     *   CharUtils.toIntValue('3', -1)  = 3
235     *   CharUtils.toIntValue('A', -1)  = -1
236     * </pre>
237     *
238     * @param ch  the character to convert
239     * @param defaultValue  the default value to use if the character is not numeric
240     * @return the int value of the character
241     */
242    public static int toIntValue(final char ch, final int defaultValue) {
243        if (!isAsciiNumeric(ch)) {
244            return defaultValue;
245        }
246        return ch - 48;
247    }
248
249    /**
250     * <p>Converts the character to the Integer it represents, throwing an
251     * exception if the character is not numeric.</p>
252     *
253     * <p>This method converts the char '1' to the int 1 and so on.</p>
254     *
255     * <pre>
256     *   CharUtils.toIntValue('3')  = 3
257     *   CharUtils.toIntValue(null) throws IllegalArgumentException
258     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
259     * </pre>
260     *
261     * @param ch  the character to convert, not null
262     * @return the int value of the character
263     * @throws NullPointerException if the Character is null
264     * @throws IllegalArgumentException if the Character is not ASCII numeric
265     */
266    public static int toIntValue(final Character ch) {
267        Validate.notNull(ch, "ch");
268        return toIntValue(ch.charValue());
269    }
270
271    /**
272     * <p>Converts the character to the Integer it represents, throwing an
273     * exception if the character is not numeric.</p>
274     *
275     * <p>This method converts the char '1' to the int 1 and so on.</p>
276     *
277     * <pre>
278     *   CharUtils.toIntValue(null, -1) = -1
279     *   CharUtils.toIntValue('3', -1)  = 3
280     *   CharUtils.toIntValue('A', -1)  = -1
281     * </pre>
282     *
283     * @param ch  the character to convert
284     * @param defaultValue  the default value to use if the character is not numeric
285     * @return the int value of the character
286     */
287    public static int toIntValue(final Character ch, final int defaultValue) {
288        if (ch == null) {
289            return defaultValue;
290        }
291        return toIntValue(ch.charValue(), defaultValue);
292    }
293
294    //-----------------------------------------------------------------------
295    /**
296     * <p>Converts the character to a String that contains the one character.</p>
297     *
298     * <p>For ASCII 7 bit characters, this uses a cache that will return the
299     * same String object each time.</p>
300     *
301     * <pre>
302     *   CharUtils.toString(' ')  = " "
303     *   CharUtils.toString('A')  = "A"
304     * </pre>
305     *
306     * @param ch  the character to convert
307     * @return a String containing the one specified character
308     */
309    public static String toString(final char ch) {
310        if (ch < 128) {
311            return CHAR_STRING_ARRAY[ch];
312        }
313        return new String(new char[] {ch});
314    }
315
316    /**
317     * <p>Converts the character to a String that contains the one character.</p>
318     *
319     * <p>For ASCII 7 bit characters, this uses a cache that will return the
320     * same String object each time.</p>
321     *
322     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
323     *
324     * <pre>
325     *   CharUtils.toString(null) = null
326     *   CharUtils.toString(' ')  = " "
327     *   CharUtils.toString('A')  = "A"
328     * </pre>
329     *
330     * @param ch  the character to convert
331     * @return a String containing the one specified character
332     */
333    public static String toString(final Character ch) {
334        if (ch == null) {
335            return null;
336        }
337        return toString(ch.charValue());
338    }
339
340    //--------------------------------------------------------------------------
341    /**
342     * <p>Converts the string to the Unicode format '\u0020'.</p>
343     *
344     * <p>This format is the Java source code format.</p>
345     *
346     * <pre>
347     *   CharUtils.unicodeEscaped(' ') = "\u0020"
348     *   CharUtils.unicodeEscaped('A') = "\u0041"
349     * </pre>
350     *
351     * @param ch  the character to convert
352     * @return the escaped Unicode string
353     */
354    public static String unicodeEscaped(final char ch) {
355        return "\\u" +
356            HEX_DIGITS[(ch >> 12) & 15] +
357            HEX_DIGITS[(ch >> 8) & 15] +
358            HEX_DIGITS[(ch >> 4) & 15] +
359            HEX_DIGITS[(ch) & 15];
360    }
361
362    /**
363     * <p>Converts the string to the Unicode format '\u0020'.</p>
364     *
365     * <p>This format is the Java source code format.</p>
366     *
367     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
368     *
369     * <pre>
370     *   CharUtils.unicodeEscaped(null) = null
371     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
372     *   CharUtils.unicodeEscaped('A')  = "\u0041"
373     * </pre>
374     *
375     * @param ch  the character to convert, may be null
376     * @return the escaped Unicode string, null if null input
377     */
378    public static String unicodeEscaped(final Character ch) {
379        if (ch == null) {
380            return null;
381        }
382        return unicodeEscaped(ch.charValue());
383    }
384
385    //--------------------------------------------------------------------------
386    /**
387     * <p>Checks whether the character is ASCII 7 bit.</p>
388     *
389     * <pre>
390     *   CharUtils.isAscii('a')  = true
391     *   CharUtils.isAscii('A')  = true
392     *   CharUtils.isAscii('3')  = true
393     *   CharUtils.isAscii('-')  = true
394     *   CharUtils.isAscii('\n') = true
395     *   CharUtils.isAscii('&copy;') = false
396     * </pre>
397     *
398     * @param ch  the character to check
399     * @return true if less than 128
400     */
401    public static boolean isAscii(final char ch) {
402        return ch < 128;
403    }
404
405    /**
406     * <p>Checks whether the character is ASCII 7 bit printable.</p>
407     *
408     * <pre>
409     *   CharUtils.isAsciiPrintable('a')  = true
410     *   CharUtils.isAsciiPrintable('A')  = true
411     *   CharUtils.isAsciiPrintable('3')  = true
412     *   CharUtils.isAsciiPrintable('-')  = true
413     *   CharUtils.isAsciiPrintable('\n') = false
414     *   CharUtils.isAsciiPrintable('&copy;') = false
415     * </pre>
416     *
417     * @param ch  the character to check
418     * @return true if between 32 and 126 inclusive
419     */
420    public static boolean isAsciiPrintable(final char ch) {
421        return ch >= 32 && ch < 127;
422    }
423
424    /**
425     * <p>Checks whether the character is ASCII 7 bit control.</p>
426     *
427     * <pre>
428     *   CharUtils.isAsciiControl('a')  = false
429     *   CharUtils.isAsciiControl('A')  = false
430     *   CharUtils.isAsciiControl('3')  = false
431     *   CharUtils.isAsciiControl('-')  = false
432     *   CharUtils.isAsciiControl('\n') = true
433     *   CharUtils.isAsciiControl('&copy;') = false
434     * </pre>
435     *
436     * @param ch  the character to check
437     * @return true if less than 32 or equals 127
438     */
439    public static boolean isAsciiControl(final char ch) {
440        return ch < 32 || ch == 127;
441    }
442
443    /**
444     * <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
445     *
446     * <pre>
447     *   CharUtils.isAsciiAlpha('a')  = true
448     *   CharUtils.isAsciiAlpha('A')  = true
449     *   CharUtils.isAsciiAlpha('3')  = false
450     *   CharUtils.isAsciiAlpha('-')  = false
451     *   CharUtils.isAsciiAlpha('\n') = false
452     *   CharUtils.isAsciiAlpha('&copy;') = false
453     * </pre>
454     *
455     * @param ch  the character to check
456     * @return true if between 65 and 90 or 97 and 122 inclusive
457     */
458    public static boolean isAsciiAlpha(final char ch) {
459        return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
460    }
461
462    /**
463     * <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
464     *
465     * <pre>
466     *   CharUtils.isAsciiAlphaUpper('a')  = false
467     *   CharUtils.isAsciiAlphaUpper('A')  = true
468     *   CharUtils.isAsciiAlphaUpper('3')  = false
469     *   CharUtils.isAsciiAlphaUpper('-')  = false
470     *   CharUtils.isAsciiAlphaUpper('\n') = false
471     *   CharUtils.isAsciiAlphaUpper('&copy;') = false
472     * </pre>
473     *
474     * @param ch  the character to check
475     * @return true if between 65 and 90 inclusive
476     */
477    public static boolean isAsciiAlphaUpper(final char ch) {
478        return ch >= 'A' && ch <= 'Z';
479    }
480
481    /**
482     * <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
483     *
484     * <pre>
485     *   CharUtils.isAsciiAlphaLower('a')  = true
486     *   CharUtils.isAsciiAlphaLower('A')  = false
487     *   CharUtils.isAsciiAlphaLower('3')  = false
488     *   CharUtils.isAsciiAlphaLower('-')  = false
489     *   CharUtils.isAsciiAlphaLower('\n') = false
490     *   CharUtils.isAsciiAlphaLower('&copy;') = false
491     * </pre>
492     *
493     * @param ch  the character to check
494     * @return true if between 97 and 122 inclusive
495     */
496    public static boolean isAsciiAlphaLower(final char ch) {
497        return ch >= 'a' && ch <= 'z';
498    }
499
500    /**
501     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
502     *
503     * <pre>
504     *   CharUtils.isAsciiNumeric('a')  = false
505     *   CharUtils.isAsciiNumeric('A')  = false
506     *   CharUtils.isAsciiNumeric('3')  = true
507     *   CharUtils.isAsciiNumeric('-')  = false
508     *   CharUtils.isAsciiNumeric('\n') = false
509     *   CharUtils.isAsciiNumeric('&copy;') = false
510     * </pre>
511     *
512     * @param ch  the character to check
513     * @return true if between 48 and 57 inclusive
514     */
515    public static boolean isAsciiNumeric(final char ch) {
516        return ch >= '0' && ch <= '9';
517    }
518
519    /**
520     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
521     *
522     * <pre>
523     *   CharUtils.isAsciiAlphanumeric('a')  = true
524     *   CharUtils.isAsciiAlphanumeric('A')  = true
525     *   CharUtils.isAsciiAlphanumeric('3')  = true
526     *   CharUtils.isAsciiAlphanumeric('-')  = false
527     *   CharUtils.isAsciiAlphanumeric('\n') = false
528     *   CharUtils.isAsciiAlphanumeric('&copy;') = false
529     * </pre>
530     *
531     * @param ch  the character to check
532     * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
533     */
534    public static boolean isAsciiAlphanumeric(final char ch) {
535        return isAsciiAlpha(ch) || isAsciiNumeric(ch);
536    }
537
538    /**
539     * <p>Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.</p>
540     *
541     * @param x the first {@code char} to compare
542     * @param y the second {@code char} to compare
543     * @return the value {@code 0} if {@code x == y};
544     *         a value less than {@code 0} if {@code x < y}; and
545     *         a value greater than {@code 0} if {@code x > y}
546     * @since 3.4
547     */
548    public static int compare(final char x, final char y) {
549        return x-y;
550    }
551}