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 behaviour 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 = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
034
035    /**
036     * {@code \u000a} linefeed LF ('\n').
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     * {@code \u000d} carriage return CR ('\r').
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      super();
075    }
076
077    //-----------------------------------------------------------------------
078    /**
079     * <p>Converts the character to a Character.</p>
080     *
081     * <p>For ASCII 7 bit characters, this uses a cache that will return the
082     * same Character object each time.</p>
083     *
084     * <pre>
085     *   CharUtils.toCharacterObject(' ')  = ' '
086     *   CharUtils.toCharacterObject('A')  = 'A'
087     * </pre>
088     *
089     * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
090     * @param ch  the character to convert
091     * @return a Character of the specified character
092     */
093    @Deprecated
094    public static Character toCharacterObject(final char ch) {
095        return Character.valueOf(ch);
096    }
097
098    /**
099     * <p>Converts the String to a Character using the first character, returning
100     * null for empty Strings.</p>
101     *
102     * <p>For ASCII 7 bit characters, this uses a cache that will return the
103     * same Character object each time.</p>
104     *
105     * <pre>
106     *   CharUtils.toCharacterObject(null) = null
107     *   CharUtils.toCharacterObject("")   = null
108     *   CharUtils.toCharacterObject("A")  = 'A'
109     *   CharUtils.toCharacterObject("BA") = 'B'
110     * </pre>
111     *
112     * @param str  the character to convert
113     * @return the Character value of the first letter of the String
114     */
115    public static Character toCharacterObject(final String str) {
116        if (StringUtils.isEmpty(str)) {
117            return null;
118        }
119        return Character.valueOf(str.charAt(0));
120    }
121
122    //-----------------------------------------------------------------------
123    /**
124     * <p>Converts the Character to a char throwing an exception for {@code null}.</p>
125     *
126     * <pre>
127     *   CharUtils.toChar(' ')  = ' '
128     *   CharUtils.toChar('A')  = 'A'
129     *   CharUtils.toChar(null) throws IllegalArgumentException
130     * </pre>
131     *
132     * @param ch  the character to convert
133     * @return the char value of the Character
134     * @throws IllegalArgumentException if the Character is null
135     */
136    public static char toChar(final Character ch) {
137        Validate.isTrue(ch != null, "The Character must not be null");
138        return ch.charValue();
139    }
140
141    /**
142     * <p>Converts the Character to a char handling {@code null}.</p>
143     *
144     * <pre>
145     *   CharUtils.toChar(null, 'X') = 'X'
146     *   CharUtils.toChar(' ', 'X')  = ' '
147     *   CharUtils.toChar('A', 'X')  = 'A'
148     * </pre>
149     *
150     * @param ch  the character to convert
151     * @param defaultValue  the value to use if the  Character is null
152     * @return the char value of the Character or the default if null
153     */
154    public static char toChar(final Character ch, final char defaultValue) {
155        if (ch == null) {
156            return defaultValue;
157        }
158        return ch.charValue();
159    }
160
161    //-----------------------------------------------------------------------
162    /**
163     * <p>Converts the String to a char using the first character, throwing
164     * an exception on empty Strings.</p>
165     *
166     * <pre>
167     *   CharUtils.toChar("A")  = 'A'
168     *   CharUtils.toChar("BA") = 'B'
169     *   CharUtils.toChar(null) throws IllegalArgumentException
170     *   CharUtils.toChar("")   throws IllegalArgumentException
171     * </pre>
172     *
173     * @param str  the character to convert
174     * @return the char value of the first letter of the String
175     * @throws IllegalArgumentException if the String is empty
176     */
177    public static char toChar(final String str) {
178        Validate.isTrue(StringUtils.isNotEmpty(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 coverts 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) == false) {
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 coverts 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) == false) {
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 coverts 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 IllegalArgumentException if the Character is not ASCII numeric or is null
264     */
265    public static int toIntValue(final Character ch) {
266        Validate.isTrue(ch != null, "The character must not be null");
267        return toIntValue(ch.charValue());
268    }
269
270    /**
271     * <p>Converts the character to the Integer it represents, throwing an
272     * exception if the character is not numeric.</p>
273     *
274     * <p>This method coverts the char '1' to the int 1 and so on.</p>
275     *
276     * <pre>
277     *   CharUtils.toIntValue(null, -1) = -1
278     *   CharUtils.toIntValue('3', -1)  = 3
279     *   CharUtils.toIntValue('A', -1)  = -1
280     * </pre>
281     *
282     * @param ch  the character to convert
283     * @param defaultValue  the default value to use if the character is not numeric
284     * @return the int value of the character
285     */
286    public static int toIntValue(final Character ch, final int defaultValue) {
287        if (ch == null) {
288            return defaultValue;
289        }
290        return toIntValue(ch.charValue(), defaultValue);
291    }
292
293    //-----------------------------------------------------------------------
294    /**
295     * <p>Converts the character to a String that contains the one character.</p>
296     *
297     * <p>For ASCII 7 bit characters, this uses a cache that will return the
298     * same String object each time.</p>
299     *
300     * <pre>
301     *   CharUtils.toString(' ')  = " "
302     *   CharUtils.toString('A')  = "A"
303     * </pre>
304     *
305     * @param ch  the character to convert
306     * @return a String containing the one specified character
307     */
308    public static String toString(final char ch) {
309        if (ch < 128) {
310            return CHAR_STRING_ARRAY[ch];
311        }
312        return new String(new char[] {ch});
313    }
314
315    /**
316     * <p>Converts the character to a String that contains the one character.</p>
317     *
318     * <p>For ASCII 7 bit characters, this uses a cache that will return the
319     * same String object each time.</p>
320     *
321     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
322     *
323     * <pre>
324     *   CharUtils.toString(null) = null
325     *   CharUtils.toString(' ')  = " "
326     *   CharUtils.toString('A')  = "A"
327     * </pre>
328     *
329     * @param ch  the character to convert
330     * @return a String containing the one specified character
331     */
332    public static String toString(final Character ch) {
333        if (ch == null) {
334            return null;
335        }
336        return toString(ch.charValue());
337    }
338
339    //--------------------------------------------------------------------------
340    /**
341     * <p>Converts the string to the Unicode format '\u0020'.</p>
342     *
343     * <p>This format is the Java source code format.</p>
344     *
345     * <pre>
346     *   CharUtils.unicodeEscaped(' ') = "\u0020"
347     *   CharUtils.unicodeEscaped('A') = "\u0041"
348     * </pre>
349     *
350     * @param ch  the character to convert
351     * @return the escaped Unicode string
352     */
353    public static String unicodeEscaped(final char ch) {
354        final StringBuilder sb = new StringBuilder(6);
355        sb.append("\\u");
356        sb.append(HEX_DIGITS[(ch >> 12) & 15]);
357        sb.append(HEX_DIGITS[(ch >> 8) & 15]);
358        sb.append(HEX_DIGITS[(ch >> 4) & 15]);
359        sb.append(HEX_DIGITS[(ch) & 15]);
360        return sb.toString();
361    }
362
363    /**
364     * <p>Converts the string to the Unicode format '\u0020'.</p>
365     *
366     * <p>This format is the Java source code format.</p>
367     *
368     * <p>If {@code null} is passed in, {@code null} will be returned.</p>
369     *
370     * <pre>
371     *   CharUtils.unicodeEscaped(null) = null
372     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
373     *   CharUtils.unicodeEscaped('A')  = "\u0041"
374     * </pre>
375     *
376     * @param ch  the character to convert, may be null
377     * @return the escaped Unicode string, null if null input
378     */
379    public static String unicodeEscaped(final Character ch) {
380        if (ch == null) {
381            return null;
382        }
383        return unicodeEscaped(ch.charValue());
384    }
385
386    //--------------------------------------------------------------------------
387    /**
388     * <p>Checks whether the character is ASCII 7 bit.</p>
389     *
390     * <pre>
391     *   CharUtils.isAscii('a')  = true
392     *   CharUtils.isAscii('A')  = true
393     *   CharUtils.isAscii('3')  = true
394     *   CharUtils.isAscii('-')  = true
395     *   CharUtils.isAscii('\n') = true
396     *   CharUtils.isAscii('&copy;') = false
397     * </pre>
398     *
399     * @param ch  the character to check
400     * @return true if less than 128
401     */
402    public static boolean isAscii(final char ch) {
403        return ch < 128;
404    }
405
406    /**
407     * <p>Checks whether the character is ASCII 7 bit printable.</p>
408     *
409     * <pre>
410     *   CharUtils.isAsciiPrintable('a')  = true
411     *   CharUtils.isAsciiPrintable('A')  = true
412     *   CharUtils.isAsciiPrintable('3')  = true
413     *   CharUtils.isAsciiPrintable('-')  = true
414     *   CharUtils.isAsciiPrintable('\n') = false
415     *   CharUtils.isAsciiPrintable('&copy;') = false
416     * </pre>
417     *
418     * @param ch  the character to check
419     * @return true if between 32 and 126 inclusive
420     */
421    public static boolean isAsciiPrintable(final char ch) {
422        return ch >= 32 && ch < 127;
423    }
424
425    /**
426     * <p>Checks whether the character is ASCII 7 bit control.</p>
427     *
428     * <pre>
429     *   CharUtils.isAsciiControl('a')  = false
430     *   CharUtils.isAsciiControl('A')  = false
431     *   CharUtils.isAsciiControl('3')  = false
432     *   CharUtils.isAsciiControl('-')  = false
433     *   CharUtils.isAsciiControl('\n') = true
434     *   CharUtils.isAsciiControl('&copy;') = false
435     * </pre>
436     *
437     * @param ch  the character to check
438     * @return true if less than 32 or equals 127
439     */
440    public static boolean isAsciiControl(final char ch) {
441        return ch < 32 || ch == 127;
442    }
443
444    /**
445     * <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
446     *
447     * <pre>
448     *   CharUtils.isAsciiAlpha('a')  = true
449     *   CharUtils.isAsciiAlpha('A')  = true
450     *   CharUtils.isAsciiAlpha('3')  = false
451     *   CharUtils.isAsciiAlpha('-')  = false
452     *   CharUtils.isAsciiAlpha('\n') = false
453     *   CharUtils.isAsciiAlpha('&copy;') = false
454     * </pre>
455     *
456     * @param ch  the character to check
457     * @return true if between 65 and 90 or 97 and 122 inclusive
458     */
459    public static boolean isAsciiAlpha(final char ch) {
460        return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
461    }
462
463    /**
464     * <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
465     *
466     * <pre>
467     *   CharUtils.isAsciiAlphaUpper('a')  = false
468     *   CharUtils.isAsciiAlphaUpper('A')  = true
469     *   CharUtils.isAsciiAlphaUpper('3')  = false
470     *   CharUtils.isAsciiAlphaUpper('-')  = false
471     *   CharUtils.isAsciiAlphaUpper('\n') = false
472     *   CharUtils.isAsciiAlphaUpper('&copy;') = false
473     * </pre>
474     *
475     * @param ch  the character to check
476     * @return true if between 65 and 90 inclusive
477     */
478    public static boolean isAsciiAlphaUpper(final char ch) {
479        return ch >= 'A' && ch <= 'Z';
480    }
481
482    /**
483     * <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
484     *
485     * <pre>
486     *   CharUtils.isAsciiAlphaLower('a')  = true
487     *   CharUtils.isAsciiAlphaLower('A')  = false
488     *   CharUtils.isAsciiAlphaLower('3')  = false
489     *   CharUtils.isAsciiAlphaLower('-')  = false
490     *   CharUtils.isAsciiAlphaLower('\n') = false
491     *   CharUtils.isAsciiAlphaLower('&copy;') = false
492     * </pre>
493     *
494     * @param ch  the character to check
495     * @return true if between 97 and 122 inclusive
496     */
497    public static boolean isAsciiAlphaLower(final char ch) {
498        return ch >= 'a' && ch <= 'z';
499    }
500
501    /**
502     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
503     *
504     * <pre>
505     *   CharUtils.isAsciiNumeric('a')  = false
506     *   CharUtils.isAsciiNumeric('A')  = false
507     *   CharUtils.isAsciiNumeric('3')  = true
508     *   CharUtils.isAsciiNumeric('-')  = false
509     *   CharUtils.isAsciiNumeric('\n') = false
510     *   CharUtils.isAsciiNumeric('&copy;') = false
511     * </pre>
512     *
513     * @param ch  the character to check
514     * @return true if between 48 and 57 inclusive
515     */
516    public static boolean isAsciiNumeric(final char ch) {
517        return ch >= '0' && ch <= '9';
518    }
519
520    /**
521     * <p>Checks whether the character is ASCII 7 bit numeric.</p>
522     *
523     * <pre>
524     *   CharUtils.isAsciiAlphanumeric('a')  = true
525     *   CharUtils.isAsciiAlphanumeric('A')  = true
526     *   CharUtils.isAsciiAlphanumeric('3')  = true
527     *   CharUtils.isAsciiAlphanumeric('-')  = false
528     *   CharUtils.isAsciiAlphanumeric('\n') = false
529     *   CharUtils.isAsciiAlphanumeric('&copy;') = false
530     * </pre>
531     *
532     * @param ch  the character to check
533     * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
534     */
535    public static boolean isAsciiAlphanumeric(final char ch) {
536        return isAsciiAlpha(ch) || isAsciiNumeric(ch);
537    }
538
539    /**
540     * <p>Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.</p>
541     *
542     * @param x the first {@code char} to compare
543     * @param y the second {@code char} to compare
544     * @return the value {@code 0} if {@code x == y};
545     *         a value less than {@code 0} if {@code x < y}; and
546     *         a value greater than {@code 0} if {@code x > y}
547     * @since 3.4
548     */
549    public static int compare(final char x, final char y) {
550        return x-y;
551    }
552}