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     */
017    package org.apache.commons.lang;
018    
019    /**
020     * <p>Operations on char primitives and Character objects.</p>
021     *
022     * <p>This class tries to handle <code>null</code> input gracefully.
023     * An exception will not be thrown for a <code>null</code> input.
024     * Each method documents its behaviour in more detail.</p>
025     * 
026     * @author Apache Software Foundation
027     * @since 2.1
028     * @version $Id: CharUtils.java 905636 2010-02-02 14:03:32Z niallp $
029     */
030    public class CharUtils {
031        
032        private static final String CHAR_STRING = 
033            "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" +
034            "\b\t\n\u000b\f\r\u000e\u000f" +
035            "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" +
036            "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
037            "\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027" +
038            "\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f" +
039            "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037" +
040            "\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f" +
041            "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047" +
042            "\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f" +
043            "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057" +
044            "\u0058\u0059\u005a\u005b\\\u005d\u005e\u005f" +
045            "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067" +
046            "\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f" +
047            "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077" +
048            "\u0078\u0079\u007a\u007b\u007c\u007d\u007e\u007f";
049        
050        private static final String[] CHAR_STRING_ARRAY = new String[128];
051        private static final Character[] CHAR_ARRAY = new Character[128];
052        
053        /**
054         * <code>\u000a</code> linefeed LF ('\n').
055         * 
056         * @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
057         *      for Character and String Literals</a>
058         * @since 2.2
059         */
060        public static final char LF = '\n';
061    
062        /**
063         * <code>\u000d</code> carriage return CR ('\r').
064         * 
065         * @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
066         *      for Character and String Literals</a>
067         * @since 2.2
068         */
069        public static final char CR = '\r';
070        
071    
072        static {
073            for (int i = 127; i >= 0; i--) {
074                CHAR_STRING_ARRAY[i] = CHAR_STRING.substring(i, i + 1);
075                CHAR_ARRAY[i] = new Character((char) i);
076            }
077        }
078    
079        /**
080         * <p><code>CharUtils</code> instances should NOT be constructed in standard programming.
081         * Instead, the class should be used as <code>CharUtils.toString('c');</code>.</p>
082         *
083         * <p>This constructor is public to permit tools that require a JavaBean instance
084         * to operate.</p>
085         */
086        public CharUtils() {
087          super();
088        }
089    
090        //-----------------------------------------------------------------------
091        /**
092         * <p>Converts the character to a Character.</p>
093         * 
094         * <p>For ASCII 7 bit characters, this uses a cache that will return the
095         * same Character object each time.</p>
096         *
097         * <pre>
098         *   CharUtils.toCharacterObject(' ')  = ' '
099         *   CharUtils.toCharacterObject('A')  = 'A'
100         * </pre>
101         *
102         * @param ch  the character to convert
103         * @return a Character of the specified character
104         */
105        public static Character toCharacterObject(char ch) {
106            if (ch < CHAR_ARRAY.length) {
107                return CHAR_ARRAY[ch];
108            }
109            return new Character(ch);
110        }
111        
112        /**
113         * <p>Converts the String to a Character using the first character, returning
114         * null for empty Strings.</p>
115         * 
116         * <p>For ASCII 7 bit characters, this uses a cache that will return the
117         * same Character object each time.</p>
118         * 
119         * <pre>
120         *   CharUtils.toCharacterObject(null) = null
121         *   CharUtils.toCharacterObject("")   = null
122         *   CharUtils.toCharacterObject("A")  = 'A'
123         *   CharUtils.toCharacterObject("BA") = 'B'
124         * </pre>
125         *
126         * @param str  the character to convert
127         * @return the Character value of the first letter of the String
128         */
129        public static Character toCharacterObject(String str) {
130            if (StringUtils.isEmpty(str)) {
131                return null;
132            }
133            return toCharacterObject(str.charAt(0));
134        }
135        
136        //-----------------------------------------------------------------------
137        /**
138         * <p>Converts the Character to a char throwing an exception for <code>null</code>.</p>
139         * 
140         * <pre>
141         *   CharUtils.toChar(null) = IllegalArgumentException
142         *   CharUtils.toChar(' ')  = ' '
143         *   CharUtils.toChar('A')  = 'A'
144         * </pre>
145         *
146         * @param ch  the character to convert
147         * @return the char value of the Character
148         * @throws IllegalArgumentException if the Character is null
149         */
150        public static char toChar(Character ch) {
151            if (ch == null) {
152                throw new IllegalArgumentException("The Character must not be null");
153            }
154            return ch.charValue();
155        }
156        
157        /**
158         * <p>Converts the Character to a char handling <code>null</code>.</p>
159         * 
160         * <pre>
161         *   CharUtils.toChar(null, 'X') = 'X'
162         *   CharUtils.toChar(' ', 'X')  = ' '
163         *   CharUtils.toChar('A', 'X')  = 'A'
164         * </pre>
165         *
166         * @param ch  the character to convert
167         * @param defaultValue  the value to use if the  Character is null
168         * @return the char value of the Character or the default if null
169         */
170        public static char toChar(Character ch, char defaultValue) {
171            if (ch == null) {
172                return defaultValue;
173            }
174            return ch.charValue();
175        }
176        
177        //-----------------------------------------------------------------------
178        /**
179         * <p>Converts the String to a char using the first character, throwing
180         * an exception on empty Strings.</p>
181         * 
182         * <pre>
183         *   CharUtils.toChar(null) = IllegalArgumentException
184         *   CharUtils.toChar("")   = IllegalArgumentException
185         *   CharUtils.toChar("A")  = 'A'
186         *   CharUtils.toChar("BA") = 'B'
187         * </pre>
188         *
189         * @param str  the character to convert
190         * @return the char value of the first letter of the String
191         * @throws IllegalArgumentException if the String is empty
192         */
193        public static char toChar(String str) {
194            if (StringUtils.isEmpty(str)) {
195                throw new IllegalArgumentException("The String must not be empty");
196            }
197            return str.charAt(0);
198        }
199        
200        /**
201         * <p>Converts the String to a char using the first character, defaulting
202         * the value on empty Strings.</p>
203         * 
204         * <pre>
205         *   CharUtils.toChar(null, 'X') = 'X'
206         *   CharUtils.toChar("", 'X')   = 'X'
207         *   CharUtils.toChar("A", 'X')  = 'A'
208         *   CharUtils.toChar("BA", 'X') = 'B'
209         * </pre>
210         *
211         * @param str  the character to convert
212         * @param defaultValue  the value to use if the  Character is null
213         * @return the char value of the first letter of the String or the default if null
214         */
215        public static char toChar(String str, char defaultValue) {
216            if (StringUtils.isEmpty(str)) {
217                return defaultValue;
218            }
219            return str.charAt(0);
220        }
221        
222        //-----------------------------------------------------------------------
223        /**
224         * <p>Converts the character to the Integer it represents, throwing an
225         * exception if the character is not numeric.</p>
226         * 
227         * <p>This method coverts the char '1' to the int 1 and so on.</p>
228         *
229         * <pre>
230         *   CharUtils.toIntValue('3')  = 3
231         *   CharUtils.toIntValue('A')  = IllegalArgumentException
232         * </pre>
233         *
234         * @param ch  the character to convert
235         * @return the int value of the character
236         * @throws IllegalArgumentException if the character is not ASCII numeric
237         */
238        public static int toIntValue(char ch) {
239            if (isAsciiNumeric(ch) == false) {
240                throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
241            }
242            return ch - 48;
243        }
244        
245        /**
246         * <p>Converts the character to the Integer it represents, throwing an
247         * exception if the character is not numeric.</p>
248         * 
249         * <p>This method coverts the char '1' to the int 1 and so on.</p>
250         *
251         * <pre>
252         *   CharUtils.toIntValue('3', -1)  = 3
253         *   CharUtils.toIntValue('A', -1)  = -1
254         * </pre>
255         *
256         * @param ch  the character to convert
257         * @param defaultValue  the default value to use if the character is not numeric
258         * @return the int value of the character
259         */
260        public static int toIntValue(char ch, int defaultValue) {
261            if (isAsciiNumeric(ch) == false) {
262                return defaultValue;
263            }
264            return ch - 48;
265        }
266        
267        /**
268         * <p>Converts the character to the Integer it represents, throwing an
269         * exception if the character is not numeric.</p>
270         * 
271         * <p>This method coverts the char '1' to the int 1 and so on.</p>
272         *
273         * <pre>
274         *   CharUtils.toIntValue(null) = IllegalArgumentException
275         *   CharUtils.toIntValue('3')  = 3
276         *   CharUtils.toIntValue('A')  = IllegalArgumentException
277         * </pre>
278         *
279         * @param ch  the character to convert, not null
280         * @return the int value of the character
281         * @throws IllegalArgumentException if the Character is not ASCII numeric or is null
282         */
283        public static int toIntValue(Character ch) {
284            if (ch == null) {
285                throw new IllegalArgumentException("The character must not be null");
286            }
287            return toIntValue(ch.charValue());
288        }
289        
290        /**
291         * <p>Converts the character to the Integer it represents, throwing an
292         * exception if the character is not numeric.</p>
293         * 
294         * <p>This method coverts the char '1' to the int 1 and so on.</p>
295         *
296         * <pre>
297         *   CharUtils.toIntValue(null, -1) = -1
298         *   CharUtils.toIntValue('3', -1)  = 3
299         *   CharUtils.toIntValue('A', -1)  = -1
300         * </pre>
301         *
302         * @param ch  the character to convert
303         * @param defaultValue  the default value to use if the character is not numeric
304         * @return the int value of the character
305         */
306        public static int toIntValue(Character ch, int defaultValue) {
307            if (ch == null) {
308                return defaultValue;
309            }
310            return toIntValue(ch.charValue(), defaultValue);
311        }
312        
313        //-----------------------------------------------------------------------
314        /**
315         * <p>Converts the character to a String that contains the one character.</p>
316         * 
317         * <p>For ASCII 7 bit characters, this uses a cache that will return the
318         * same String object each time.</p>
319         *
320         * <pre>
321         *   CharUtils.toString(' ')  = " "
322         *   CharUtils.toString('A')  = "A"
323         * </pre>
324         *
325         * @param ch  the character to convert
326         * @return a String containing the one specified character
327         */
328        public static String toString(char ch) {
329            if (ch < 128) {
330                return CHAR_STRING_ARRAY[ch];
331            }
332            return new String(new char[] {ch});
333        }
334        
335        /**
336         * <p>Converts the character to a String that contains the one character.</p>
337         * 
338         * <p>For ASCII 7 bit characters, this uses a cache that will return the
339         * same String object each time.</p>
340         * 
341         * <p>If <code>null</code> is passed in, <code>null</code> will be returned.</p>
342         *
343         * <pre>
344         *   CharUtils.toString(null) = null
345         *   CharUtils.toString(' ')  = " "
346         *   CharUtils.toString('A')  = "A"
347         * </pre>
348         *
349         * @param ch  the character to convert
350         * @return a String containing the one specified character
351         */
352        public static String toString(Character ch) {
353            if (ch == null) {
354                return null;
355            }
356            return toString(ch.charValue());
357        }
358        
359        //--------------------------------------------------------------------------
360        /**
361         * <p>Converts the string to the unicode format '\u0020'.</p>
362         * 
363         * <p>This format is the Java source code format.</p>
364         *
365         * <pre>
366         *   CharUtils.unicodeEscaped(' ') = "\u0020"
367         *   CharUtils.unicodeEscaped('A') = "\u0041"
368         * </pre>
369         * 
370         * @param ch  the character to convert
371         * @return the escaped unicode string
372         */
373        public static String unicodeEscaped(char ch) {
374            if (ch < 0x10) {
375                return "\\u000" + Integer.toHexString(ch);
376            } else if (ch < 0x100) {
377                return "\\u00" + Integer.toHexString(ch);
378            } else if (ch < 0x1000) {
379                return "\\u0" + Integer.toHexString(ch);
380            }
381            return "\\u" + Integer.toHexString(ch);
382        }
383        
384        /**
385         * <p>Converts the string to the unicode format '\u0020'.</p>
386         * 
387         * <p>This format is the Java source code format.</p>
388         * 
389         * <p>If <code>null</code> is passed in, <code>null</code> will be returned.</p>
390         *
391         * <pre>
392         *   CharUtils.unicodeEscaped(null) = null
393         *   CharUtils.unicodeEscaped(' ')  = "\u0020"
394         *   CharUtils.unicodeEscaped('A')  = "\u0041"
395         * </pre>
396         * 
397         * @param ch  the character to convert, may be null
398         * @return the escaped unicode string, null if null input
399         */
400        public static String unicodeEscaped(Character ch) {
401            if (ch == null) {
402                return null;
403            }
404            return unicodeEscaped(ch.charValue());
405        }
406        
407        //--------------------------------------------------------------------------
408        /**
409         * <p>Checks whether the character is ASCII 7 bit.</p>
410         *
411         * <pre>
412         *   CharUtils.isAscii('a')  = true
413         *   CharUtils.isAscii('A')  = true
414         *   CharUtils.isAscii('3')  = true
415         *   CharUtils.isAscii('-')  = true
416         *   CharUtils.isAscii('\n') = true
417         *   CharUtils.isAscii('&copy;') = false
418         * </pre>
419         * 
420         * @param ch  the character to check
421         * @return true if less than 128
422         */
423        public static boolean isAscii(char ch) {
424            return ch < 128;
425        }
426        
427        /**
428         * <p>Checks whether the character is ASCII 7 bit printable.</p>
429         *
430         * <pre>
431         *   CharUtils.isAsciiPrintable('a')  = true
432         *   CharUtils.isAsciiPrintable('A')  = true
433         *   CharUtils.isAsciiPrintable('3')  = true
434         *   CharUtils.isAsciiPrintable('-')  = true
435         *   CharUtils.isAsciiPrintable('\n') = false
436         *   CharUtils.isAsciiPrintable('&copy;') = false
437         * </pre>
438         * 
439         * @param ch  the character to check
440         * @return true if between 32 and 126 inclusive
441         */
442        public static boolean isAsciiPrintable(char ch) {
443            return ch >= 32 && ch < 127;
444        }
445        
446        /**
447         * <p>Checks whether the character is ASCII 7 bit control.</p>
448         *
449         * <pre>
450         *   CharUtils.isAsciiControl('a')  = false
451         *   CharUtils.isAsciiControl('A')  = false
452         *   CharUtils.isAsciiControl('3')  = false
453         *   CharUtils.isAsciiControl('-')  = false
454         *   CharUtils.isAsciiControl('\n') = true
455         *   CharUtils.isAsciiControl('&copy;') = false
456         * </pre>
457         * 
458         * @param ch  the character to check
459         * @return true if less than 32 or equals 127
460         */
461        public static boolean isAsciiControl(char ch) {
462            return ch < 32 || ch == 127;
463        }
464        
465        /**
466         * <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
467         *
468         * <pre>
469         *   CharUtils.isAsciiAlpha('a')  = true
470         *   CharUtils.isAsciiAlpha('A')  = true
471         *   CharUtils.isAsciiAlpha('3')  = false
472         *   CharUtils.isAsciiAlpha('-')  = false
473         *   CharUtils.isAsciiAlpha('\n') = false
474         *   CharUtils.isAsciiAlpha('&copy;') = false
475         * </pre>
476         * 
477         * @param ch  the character to check
478         * @return true if between 65 and 90 or 97 and 122 inclusive
479         */
480        public static boolean isAsciiAlpha(char ch) {
481            return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
482        }
483        
484        /**
485         * <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
486         *
487         * <pre>
488         *   CharUtils.isAsciiAlphaUpper('a')  = false
489         *   CharUtils.isAsciiAlphaUpper('A')  = true
490         *   CharUtils.isAsciiAlphaUpper('3')  = false
491         *   CharUtils.isAsciiAlphaUpper('-')  = false
492         *   CharUtils.isAsciiAlphaUpper('\n') = false
493         *   CharUtils.isAsciiAlphaUpper('&copy;') = false
494         * </pre>
495         * 
496         * @param ch  the character to check
497         * @return true if between 65 and 90 inclusive
498         */
499        public static boolean isAsciiAlphaUpper(char ch) {
500            return ch >= 'A' && ch <= 'Z';
501        }
502        
503        /**
504         * <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
505         *
506         * <pre>
507         *   CharUtils.isAsciiAlphaLower('a')  = true
508         *   CharUtils.isAsciiAlphaLower('A')  = false
509         *   CharUtils.isAsciiAlphaLower('3')  = false
510         *   CharUtils.isAsciiAlphaLower('-')  = false
511         *   CharUtils.isAsciiAlphaLower('\n') = false
512         *   CharUtils.isAsciiAlphaLower('&copy;') = false
513         * </pre>
514         * 
515         * @param ch  the character to check
516         * @return true if between 97 and 122 inclusive
517         */
518        public static boolean isAsciiAlphaLower(char ch) {
519            return ch >= 'a' && ch <= 'z';
520        }
521        
522        /**
523         * <p>Checks whether the character is ASCII 7 bit numeric.</p>
524         *
525         * <pre>
526         *   CharUtils.isAsciiNumeric('a')  = false
527         *   CharUtils.isAsciiNumeric('A')  = false
528         *   CharUtils.isAsciiNumeric('3')  = true
529         *   CharUtils.isAsciiNumeric('-')  = false
530         *   CharUtils.isAsciiNumeric('\n') = false
531         *   CharUtils.isAsciiNumeric('&copy;') = false
532         * </pre>
533         * 
534         * @param ch  the character to check
535         * @return true if between 48 and 57 inclusive
536         */
537        public static boolean isAsciiNumeric(char ch) {
538            return ch >= '0' && ch <= '9';
539        }
540        
541        /**
542         * <p>Checks whether the character is ASCII 7 bit numeric.</p>
543         *
544         * <pre>
545         *   CharUtils.isAsciiAlphanumeric('a')  = true
546         *   CharUtils.isAsciiAlphanumeric('A')  = true
547         *   CharUtils.isAsciiAlphanumeric('3')  = true
548         *   CharUtils.isAsciiAlphanumeric('-')  = false
549         *   CharUtils.isAsciiAlphanumeric('\n') = false
550         *   CharUtils.isAsciiAlphanumeric('&copy;') = false
551         * </pre>
552         * 
553         * @param ch  the character to check
554         * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
555         */
556        public static boolean isAsciiAlphanumeric(char ch) {
557            return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
558        }
559        
560    }