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