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    static {
055        for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
056            CHAR_STRING_ARRAY[c] = String.valueOf(c);
057        }
058    }
059
060    /**
061     * <p>{@code CharUtils} instances should NOT be constructed in standard programming.
062     * Instead, the class should be used as {@code CharUtils.toString('c');}.</p>
063     *
064     * <p>This constructor is public to permit tools that require a JavaBean instance
065     * to operate.</p>
066     */
067    public CharUtils() {
068      super();
069    }
070
071    //-----------------------------------------------------------------------
072    /**
073     * <p>Converts the character to a Character.</p>
074     * 
075     * <p>For ASCII 7 bit characters, this uses a cache that will return the
076     * same Character object each time.</p>
077     *
078     * <pre>
079     *   CharUtils.toCharacterObject(' ')  = ' '
080     *   CharUtils.toCharacterObject('A')  = 'A'
081     * </pre>
082     *
083     * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
084     * @param ch  the character to convert
085     * @return a Character of the specified character
086     */
087    @Deprecated
088    public static Character toCharacterObject(final char ch) {
089        return Character.valueOf(ch);
090    }
091    
092    /**
093     * <p>Converts the String to a Character using the first character, returning
094     * null for empty Strings.</p>
095     * 
096     * <p>For ASCII 7 bit characters, this uses a cache that will return the
097     * same Character object each time.</p>
098     * 
099     * <pre>
100     *   CharUtils.toCharacterObject(null) = null
101     *   CharUtils.toCharacterObject("")   = null
102     *   CharUtils.toCharacterObject("A")  = 'A'
103     *   CharUtils.toCharacterObject("BA") = 'B'
104     * </pre>
105     *
106     * @param str  the character to convert
107     * @return the Character value of the first letter of the String
108     */
109    public static Character toCharacterObject(final String str) {
110        if (StringUtils.isEmpty(str)) {
111            return null;
112        }
113        return Character.valueOf(str.charAt(0));
114    }
115    
116    //-----------------------------------------------------------------------
117    /**
118     * <p>Converts the Character to a char throwing an exception for {@code null}.</p>
119     * 
120     * <pre>
121     *   CharUtils.toChar(' ')  = ' '
122     *   CharUtils.toChar('A')  = 'A'
123     *   CharUtils.toChar(null) throws IllegalArgumentException
124     * </pre>
125     *
126     * @param ch  the character to convert
127     * @return the char value of the Character
128     * @throws IllegalArgumentException if the Character is null
129     */
130    public static char toChar(final Character ch) {
131        if (ch == null) {
132            throw new IllegalArgumentException("The Character must not be null");
133        }
134        return ch.charValue();
135    }
136    
137    /**
138     * <p>Converts the Character to a char handling {@code null}.</p>
139     * 
140     * <pre>
141     *   CharUtils.toChar(null, 'X') = 'X'
142     *   CharUtils.toChar(' ', 'X')  = ' '
143     *   CharUtils.toChar('A', 'X')  = 'A'
144     * </pre>
145     *
146     * @param ch  the character to convert
147     * @param defaultValue  the value to use if the  Character is null
148     * @return the char value of the Character or the default if null
149     */
150    public static char toChar(final Character ch, final char defaultValue) {
151        if (ch == null) {
152            return defaultValue;
153        }
154        return ch.charValue();
155    }
156    
157    //-----------------------------------------------------------------------
158    /**
159     * <p>Converts the String to a char using the first character, throwing
160     * an exception on empty Strings.</p>
161     * 
162     * <pre>
163     *   CharUtils.toChar("A")  = 'A'
164     *   CharUtils.toChar("BA") = 'B'
165     *   CharUtils.toChar(null) throws IllegalArgumentException
166     *   CharUtils.toChar("")   throws IllegalArgumentException
167     * </pre>
168     *
169     * @param str  the character to convert
170     * @return the char value of the first letter of the String
171     * @throws IllegalArgumentException if the String is empty
172     */
173    public static char toChar(final String str) {
174        if (StringUtils.isEmpty(str)) {
175            throw new IllegalArgumentException("The String must not be empty");
176        }
177        return str.charAt(0);
178    }
179    
180    /**
181     * <p>Converts the String to a char using the first character, defaulting
182     * the value on empty Strings.</p>
183     * 
184     * <pre>
185     *   CharUtils.toChar(null, 'X') = 'X'
186     *   CharUtils.toChar("", 'X')   = 'X'
187     *   CharUtils.toChar("A", 'X')  = 'A'
188     *   CharUtils.toChar("BA", 'X') = 'B'
189     * </pre>
190     *
191     * @param str  the character to convert
192     * @param defaultValue  the value to use if the  Character is null
193     * @return the char value of the first letter of the String or the default if null
194     */
195    public static char toChar(final String str, final char defaultValue) {
196        if (StringUtils.isEmpty(str)) {
197            return defaultValue;
198        }
199        return str.charAt(0);
200    }
201    
202    //-----------------------------------------------------------------------
203    /**
204     * <p>Converts the character to the Integer it represents, throwing an
205     * exception if the character is not numeric.</p>
206     * 
207     * <p>This method coverts the char '1' to the int 1 and so on.</p>
208     *
209     * <pre>
210     *   CharUtils.toIntValue('3')  = 3
211     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
212     * </pre>
213     *
214     * @param ch  the character to convert
215     * @return the int value of the character
216     * @throws IllegalArgumentException if the character is not ASCII numeric
217     */
218    public static int toIntValue(final char ch) {
219        if (isAsciiNumeric(ch) == false) {
220            throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
221        }
222        return ch - 48;
223    }
224    
225    /**
226     * <p>Converts the character to the Integer it represents, throwing an
227     * exception if the character is not numeric.</p>
228     * 
229     * <p>This method coverts the char '1' to the int 1 and so on.</p>
230     *
231     * <pre>
232     *   CharUtils.toIntValue('3', -1)  = 3
233     *   CharUtils.toIntValue('A', -1)  = -1
234     * </pre>
235     *
236     * @param ch  the character to convert
237     * @param defaultValue  the default value to use if the character is not numeric
238     * @return the int value of the character
239     */
240    public static int toIntValue(final char ch, final int defaultValue) {
241        if (isAsciiNumeric(ch) == false) {
242            return defaultValue;
243        }
244        return ch - 48;
245    }
246    
247    /**
248     * <p>Converts the character to the Integer it represents, throwing an
249     * exception if the character is not numeric.</p>
250     * 
251     * <p>This method coverts the char '1' to the int 1 and so on.</p>
252     *
253     * <pre>
254     *   CharUtils.toIntValue('3')  = 3
255     *   CharUtils.toIntValue(null) throws IllegalArgumentException
256     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
257     * </pre>
258     *
259     * @param ch  the character to convert, not null
260     * @return the int value of the character
261     * @throws IllegalArgumentException if the Character is not ASCII numeric or is null
262     */
263    public static int toIntValue(final Character ch) {
264        if (ch == null) {
265            throw new IllegalArgumentException("The character must not be null");
266        }
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        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(char x, char y) {
550        return x-y;
551    }
552}