001    package railo.commons.lang;
002    
003    import java.io.UnsupportedEncodingException;
004    
005    import railo.commons.io.SystemUtil;
006    import railo.runtime.op.Caster;
007    import railo.runtime.type.Collection;
008    
009    
010    
011    
012    
013    /**
014     * Util to do some additional String Operations
015     */
016    public final class StringUtil {
017        
018            /**
019             * do first Letter Upper case
020             * @param str String to operate
021             * @return uppercase string
022             */
023            public static String ucFirst(String str) {
024                    if(str==null) return null;
025                    else if(str.length()<=1) return str.toUpperCase();
026                    else {
027                            return str.substring(0,1).toUpperCase()+str.substring(1);
028                    }
029            }
030            
031            /**
032             * do first Letter Upper case
033             * @param str String to operate
034             * @return lower case String
035             */
036            public static String lcFirst(String str) {
037                    if(str==null) return null;
038                    else if(str.length()<=1) return str.toLowerCase();
039                    else {
040                            return str.substring(0,1).toLowerCase()+str.substring(1);
041                    }
042            }
043            
044            /**
045             * Unescapes HTML Tags
046             * @param html html code  to escape
047             * @return escaped html code
048             */
049            public static String unescapeHTML(String html) {
050                    return HTMLEntities.unescapeHTML(html);
051            }
052            
053            /**
054             * Escapes XML Tags
055             * @param html html code to unescape
056             * @return unescaped html code
057             */
058            public static String escapeHTML(String html) {
059                    return HTMLEntities.escapeHTML(html);
060            }
061            
062            /**
063             * escapes JS sensitive characters
064             * @param str String to escape
065             * @return escapes String
066             */
067            public static String escapeJS(String str) {
068                    char[] arr=str.toCharArray();
069                    StringBuilder rtn=new StringBuilder(arr.length);
070                    for(int i=0;i<arr.length;i++) {
071                            switch(arr[i]) {
072                                    case '\\': rtn.append("\\\\"); break;
073                                    case '\n': rtn.append("\\n"); break;
074                                    case '\r': rtn.append("\\r"); break;
075                                    case '\f': rtn.append("\\f"); break;
076                                    case '\b': rtn.append("\\b"); break;
077                                    case '\t': rtn.append("\\t"); break;
078                                    case '"' : rtn.append("\\\""); break;
079                                    case '\'': rtn.append("\\\'"); break;
080                                    default : rtn.append(arr[i]); break;
081                            }
082                    }
083                    return rtn.toString();
084            }
085    
086            /**
087             * reapeats a string
088             * @param str string to repeat
089             * @param count how many time string will be reapeted
090             * @return reapted string
091             */
092        public static String repeatString(String str,int count) {
093            if(count<=0) return "";
094            char[] chars = str.toCharArray();
095            char[] rtn=new char[chars.length*count];
096            int pos=0;
097            for(int i=0;i<count;i++) {
098                for(int y=0;y<chars.length;y++)rtn[pos++]=chars[y];
099                //rtn.append(str);
100            }
101            return new String(rtn);
102        }
103    
104            /**
105             * translate, like method toString, a object to a string, but when value is null value will be translated to a empty String (""). 
106             * @param o Object to convert
107             * @return converted String
108             */
109            public static String toStringEmptyIfNull(Object o) {
110                    if(o==null)return "";
111                    return o.toString();
112            }
113            
114            public static String emptyIfNull(String str) {
115                    if(str==null)return "";
116                    return str;
117            }
118            
119            public static String emptyIfNull(Collection.Key key) {
120                    if(key==null)return "";
121                    return key.getString();
122            }
123            
124            /**
125             * escape all special characters of the regular expresson language
126             * @param str String to escape
127             * @return escaped String
128             */
129            public static String reqExpEscape(String str) {
130                    char[] arr = str.toCharArray();
131                    StringBuilder sb=new StringBuilder(str.length()*2);
132                    
133                    for(int i=0;i<arr.length;i++) {
134                            sb.append('\\');
135                            sb.append(arr[i]);
136                    }
137                    
138                    return sb.toString();
139            }
140            
141            /**
142             * translate a string to a valid identity variable name
143             * @param varName variable name template to translate
144             * @return translated variable name
145             */
146            public static String toIdentityVariableName(String varName) {
147                    char[] chars=varName.toCharArray();
148                    long changes=0;
149    
150                    StringBuilder rtn=new StringBuilder(chars.length+2);
151                    rtn.append("CF");               
152                    
153                    for(int i=0;i<chars.length;i++) {
154                            char c=chars[i];
155                            if((c>='a' && c<='z') ||(c>='A' && c<='Z') ||(c>='0' && c<='9'))
156                                    rtn.append(c);
157                            else {  
158                                    rtn.append('_');
159                                    changes+=(c*(i+1));
160                            }
161                    }
162                    
163                    return rtn.append(changes).toString();
164            }
165            /**
166             * translate a string to a valid classname string
167             * @param str string to translate
168             * @return translated String
169             */
170            public static String toClassName(String str) {
171                    StringBuilder rtn=new StringBuilder();
172                    String[] arr=str.split("[\\\\|//]");
173                    for(int i=0;i<arr.length;i++) {
174                            if(arr[i].length()==0)continue;
175                            if(rtn.length()!=0)rtn.append('.');
176                            char[] chars=arr[i].toCharArray();
177                            long changes=0;
178                            for(int y=0;y<chars.length;y++) {
179                                    char c=chars[y];
180                                    if(y==0 && (c>='0' && c<='9'))rtn.append("_"+c);
181                                    else if((c>='a' && c<='z') ||(c>='A' && c<='Z') ||(c>='0' && c<='9'))
182                                            rtn.append(c);
183                                    else {  
184                                            rtn.append('_');
185                                            changes+=(c*(i+1));
186                                    }
187                            }
188                            if(changes>0)rtn.append(changes);
189                    }
190                    return rtn.toString();
191            }
192    
193            /**
194             * translate a string to a valid variable string
195             * @param str string to translate
196             * @return translated String
197             */
198    
199            public static String toVariableName(String str) {
200                    return toVariableName(str, true);
201            }
202            public static String toVariableName(String str, boolean addIdentityNumber) {
203                    
204                    StringBuilder rtn=new StringBuilder();
205                    char[] chars=str.toCharArray();
206                    long changes=0;
207                    boolean doCorrect=true;
208                    for(int i=0;i<chars.length;i++) {
209                            char c=chars[i];
210                            if(i==0 && (c>='0' && c<='9'))rtn.append("_"+c);
211                            else if((c>='a' && c<='z') ||(c>='A' && c<='Z') ||(c>='0' && c<='9') || c=='_' || c=='$')
212                                    rtn.append(c);
213                            else {  
214                                doCorrect=false;
215                                    rtn.append('_');
216                                    //if(!(c=='.' && str.substring(i).equals(".cfm")))
217                                    changes+=(c*(i+1));
218                            }
219                    }
220                    
221                    if(addIdentityNumber && changes>0)rtn.append(changes);
222                    //print.ln(" - "+rtn);
223                    
224                    if(doCorrect)return correctReservedWord(rtn.toString());
225                    return rtn.toString();
226            }
227            
228    
229            /**
230             * if given string is a keyword it will be replaced with none keyword
231             * @param str
232             * @return corrected word
233             */
234            private static String correctReservedWord(String str) {
235                    char first=str.charAt(0);
236                    
237                    switch(first) {
238                    case 'a':
239                            if(str.equals("abstract")) return "_"+str;
240                    break;
241                    case 'b':
242                            if(str.equals("boolean")) return "_"+str;
243                            else if(str.equals("break")) return "_"+str;
244                            else if(str.equals("byte")) return "_"+str;
245                    break;
246                    case 'c':
247                            if(str.equals("case")) return "_"+str;
248                            else if(str.equals("catch")) return "_"+str;
249                            else if(str.equals("char")) return "_"+str;
250                            else if(str.equals("const")) return "_"+str;
251                            else if(str.equals("class")) return "_"+str;
252                            else if(str.equals("continue")) return "_"+str;
253                    break;
254                    case 'd':
255                            if(str.equals("default")) return "_"+str;
256                            else if(str.equals("do")) return "_"+str;
257                            else if(str.equals("double")) return "_"+str;
258                    break;
259                    case 'e':
260                            if(str.equals("else")) return "_"+str;
261                            else if(str.equals("extends")) return "_"+str;
262                            else if(str.equals("enum")) return "_"+str;
263                    break;
264                    case 'f':
265                            if(str.equals("false")) return "_"+str;
266                            else if(str.equals("final")) return "_"+str;
267                            else if(str.equals("finally")) return "_"+str;
268                            else if(str.equals("float")) return "_"+str;
269                            else if(str.equals("for")) return "_"+str;
270                    break;
271                    case 'g':
272                            if(str.equals("goto")) return "_"+str;
273                    break;
274                    case 'i':
275                            if(str.equals("if")) return "_"+str;
276                            else if(str.equals("implements")) return "_"+str;
277                            else if(str.equals("import")) return "_"+str;
278                            else if(str.equals("instanceof")) return "_"+str;
279                            else if(str.equals("int")) return "_"+str;
280                            else if(str.equals("interface")) return "_"+str;
281                    break;
282                    case 'n':
283                            if(str.equals("native")) return "_"+str;
284                            else if(str.equals("new")) return "_"+str;
285                            else if(str.equals("null")) return "_"+str;
286                    break;
287                    case 'p':
288                            if(str.equals("package")) return "_"+str;
289                            else if(str.equals("private")) return "_"+str;
290                            else if(str.equals("protected")) return "_"+str;
291                            else if(str.equals("public")) return "_"+str;
292                    break;
293                    case 'r':
294                            if(str.equals("return")) return "_"+str;
295                    break;
296                    case 's':
297                            if(str.equals("short")) return "_"+str;
298                            else if(str.equals("static")) return "_"+str;
299                            else if(str.equals("strictfp")) return "_"+str;
300                            else if(str.equals("super")) return "_"+str;
301                            else if(str.equals("switch")) return "_"+str;
302                            else if(str.equals("synchronized")) return "_"+str;
303                    break;
304                    case 't':
305                            if(str.equals("this")) return "_"+str;
306                            else if(str.equals("throw")) return "_"+str;
307                            else if(str.equals("throws")) return "_"+str;
308                            else if(str.equals("transient")) return "_"+str;
309                            else if(str.equals("true")) return "_"+str;
310                            else if(str.equals("try")) return "_"+str;
311                    break;
312                    case 'v':
313                            if(str.equals("void")) return "_"+str;
314                            else if(str.equals("volatile")) return "_"+str;
315                    break;
316                    case 'w':
317                            if(str.equals("while")) return "_"+str;
318                    break;
319                    }
320                    return str;
321                    
322            }
323            
324            /** 
325         * This function returns a string with whitespace stripped from the beginning of str 
326         * @param str String to clean 
327         * @return cleaned String 
328         */ 
329        public static String ltrim(String str,String defaultValue) { 
330                    if(str==null) return defaultValue;
331                int len = str.length(); 
332                int st = 0; 
333    
334                while ((st < len) && (str.charAt(st) <= ' ')) { 
335                    st++; 
336                } 
337                return ((st > 0)) ? str.substring(st) : str; 
338        } 
339        
340        /** 
341         * This function returns a string with whitespace stripped from the end of str 
342         * @param str String to clean 
343         * @return cleaned String 
344         */ 
345        public static String rtrim(String str,String defaultValue) { 
346            if(str==null) return defaultValue;
347                int len = str.length(); 
348    
349                while ((0 < len) && (str.charAt(len-1) <= ' ')) { 
350                    len--; 
351                } 
352                return (len < str.length()) ? str.substring(0, len) : str; 
353        }   
354        
355    
356    
357        /**
358         * return if in a string are line feeds or not
359         * @param str string to check
360         * @return translated string
361         */
362        public static boolean hasLineFeed(String str) {
363            int len=str.length();
364            char c;
365            for(int i=0;i<len;i++) {
366                c=str.charAt(i);
367                if(c=='\n' || c=='\r') return true;
368            }
369            return false;
370        }
371    
372        /**
373         * remove all white spaces followd by whitespaces
374         * @param str strring to translate
375         * @return translated string
376         */
377        public static String suppressWhiteSpace(String str) {
378            int len=str.length();
379            StringBuilder sb=new StringBuilder(len);
380            //boolean wasWS=false;
381            
382            char c;
383            char buffer=0;
384            for(int i=0;i<len;i++) {
385                c=str.charAt(i);
386                if(c=='\n' || c=='\r')              buffer='\n';
387                else if(c==' ' || c=='\t')  {
388                    if(buffer==0)buffer=c;
389                }
390                else {
391                    if(buffer!=0){
392                            sb.append(buffer);
393                            buffer=0;
394                    }
395                    sb.append(c);
396                }
397                //sb.append(c);
398            }
399            if(buffer!=0)sb.append(buffer);
400            
401            return sb.toString();
402        }
403            
404    
405    
406        /**
407         * returns string, if given string is null or lengt 0 return default value
408         * @param value
409         * @param defaultValue
410         * @return value or default value
411         */
412        public static String toString(String value, String defaultValue) {
413            return value==null || value.length()==0?defaultValue:value;
414        }
415    
416        /**
417         * returns string, if given string is null or lengt 0 return default value
418         * @param value
419         * @param defaultValue
420         * @return value or default value
421         */
422        public static String toString(Object value, String defaultValue) {
423            if(value==null) return defaultValue;
424            return toString(value.toString(), defaultValue);
425        }
426    
427        /**
428         * cut string to max size if the string is greater, otherweise to nothing
429         * @param content
430         * @param max 
431         * @return cutted string
432         */
433        
434        public static String max(String content,int max) {
435            return max(content, max,"");
436        }
437        
438        public static String max(String content,int max, String dotDotDot) {
439            if(content==null) return null;
440            if(content.length()<=max) return content;
441            
442            return content.substring(0,max)+dotDotDot;
443        }
444        
445    
446        /**
447         * @param str String to work with
448         * @param sub1 value to replace
449         * @param sub2 replacement
450         * @param onlyFirst replace only first or all 
451         * @return new String
452         */
453        public static String replace(String str, String sub1, String sub2, boolean onlyFirst) {
454            if(sub1.equals(sub2)) return str;
455            
456            if(!onlyFirst && sub1.length()==1 && sub2.length()==1)return str.replace(sub1.charAt(0),sub2.charAt(0));
457            
458            
459            StringBuilder sb=new StringBuilder();
460            int start=0;
461            int pos;
462            int sub1Length=sub1.length();
463            
464            while((pos=str.indexOf(sub1,start))!=-1){
465                sb.append(str.substring(start,pos));
466                sb.append(sub2);
467                start=pos+sub1Length;
468                if(onlyFirst)break;
469            }
470            sb.append(str.substring(start));
471            
472            return sb.toString();
473        }
474        
475        /**
476         * adds zeros add the begin of a int example: addZeros(2,3) return "002"
477         * @param i number to add nulls
478         * @param size 
479         * @return min len of return value;
480         */
481        public static String addZeros(int i, int size) {
482            String rtn=Caster.toString(i);
483            if(rtn.length()<size) return repeatString("0",size-rtn.length())+rtn;
484            return rtn;
485        }
486    
487        
488        /**
489         * adds zeros add the begin of a int example: addZeros(2,3) return "002"
490         * @param i number to add nulls
491         * @param size 
492         * @return min len of return value;
493         */
494        public static String addZeros(long i, int size) {
495            String rtn=Caster.toString(i);
496            if(rtn.length()<size) return repeatString("0",size-rtn.length())+rtn;
497            return rtn;
498        }
499    
500            public static int indexOf(String haystack, String needle) {
501                    if(haystack==null) return -1;
502                    return haystack.indexOf(needle);
503            }
504            
505            public static int indexOfIgnoreCase(String haystack, String needle) {
506                    if(StringUtil.isEmpty(haystack) || StringUtil.isEmpty(needle)) return -1;
507                    needle=needle.toLowerCase();
508                    
509                    int lenHaystack=haystack.length();
510                    int lenNeedle=needle.length();
511                    
512                    char lastNeedle=needle.charAt(lenNeedle-1);
513                    char c;
514                    outer:for(int i=lenNeedle-1;i<lenHaystack;i++) {
515                            c=Character.toLowerCase(haystack.charAt(i));
516                            if(c==lastNeedle) {
517                                    for(int y=0;y<lenNeedle-1;y++) {
518                                            if(needle.charAt(y)!=Character.toLowerCase(haystack.charAt(i-(lenNeedle-1)+y)))
519                                                            continue outer;
520                                    }
521                                    return i-(lenNeedle-1);
522                            }
523                    }
524                    
525                    
526                    return -1;
527            }
528        
529        /**
530         * Tests if this string starts with the specified prefix.
531         * @param str string to check first char
532         * @param prefix the prefix.
533         * @return is first of given type
534         */
535        public static boolean startsWith(String str, char prefix) {
536            return str!=null && str.length()>0 && str.charAt(0)==prefix;
537        }
538        
539        /**
540         * Tests if this string ends with the specified suffix.
541         * @param str string to check first char
542         * @param suffix the suffix.
543         * @return is last of given type
544         */
545        public static boolean endsWith(String str, char suffix) {
546            return str!=null && str.length()>0 && str.charAt(str.length()-1)==suffix;
547        }
548    
549        /**
550         * Tests if this string ends with the specified suffix.
551         * @param str string to check first char
552         * @param suffix the suffix.
553         * @return is last of given type
554         */
555        /**
556         * Helper functions to query a strings start portion. The comparison is case insensitive.
557         *
558         * @param base  the base string.
559         * @param start  the starting text.
560         *
561         * @return true, if the string starts with the given starting text.
562         */
563        public static boolean startsWithIgnoreCase(final String base, final String start) {
564            if (base.length() < start.length()) {
565                return false;
566            }
567            return base.regionMatches(true, 0, start, 0, start.length());
568        }
569    
570        /**
571         * Helper functions to query a strings end portion. The comparison is case insensitive.
572         *
573         * @param base  the base string.
574         * @param end  the ending text.
575         *
576         * @return true, if the string ends with the given ending text.
577         */
578        public static boolean endsWithIgnoreCase(final String base, final String end) {
579            if (base.length() < end.length()) {
580                return false;
581            }
582            return base.regionMatches(true, base.length() - end.length(), end, 0, end.length());
583        }
584    
585        
586    
587        /**
588         * returns if byte arr is a BOM character Stream (UTF-8,UTF-16)
589        * @param barr
590        * @return is BOM or not
591        */
592       public static  boolean isBOM(byte[] barr) {
593            return barr.length>=3 && barr[0]==0xEF && barr[1]==0xBB && barr[2]==0xBF;
594        }
595    
596        /**
597         * return "" if value is null otherwise return same string
598         * @param str
599         * @return string (not null)
600         */
601        public static String valueOf(String str) {
602            if(str==null)return "";
603            return str;
604        }
605    
606        
607        /**
608         * cast a string a lower case String, is faster than the String.toLowerCase, if all Character are already Low Case
609         * @param str
610         * @return lower case value
611         */
612        public static String toLowerCase(String str) {
613            int len=str.length();
614            char c;
615            for(int i=0;i<len;i++) {
616                c=str.charAt(i);
617                if(!((c>='a' && c<='z') || (c>='0' && c<='9'))) {
618                    return str.toLowerCase();
619                }
620            }
621            
622            return str;
623        }
624        public static String toUpperCase(String str) {
625            int len=str.length();
626            char c;
627            for(int i=0;i<len;i++) {
628                c=str.charAt(i);
629                if(!((c>='A' && c<='Z') || (c>='0' && c<='9'))) {
630                    return str.toUpperCase();
631                }
632            }
633            
634            return str;
635        }
636    
637        /**
638         * soundex function
639         * @param str
640         * @return soundex from given string
641         */
642        public static String soundex(String str) {
643            return new org.apache.commons.codec.language.Soundex().soundex(str);
644        }
645    
646        /**
647         * return the last character of a string, if string ist empty return 0;
648         * @param str string to get last character
649         * @return last character
650         */
651        public static char lastChar(String str) {
652            if(str==null || str.length()==0) return 0;
653            return str.charAt(str.length()-1);
654        }
655        
656    
657        /**
658         * 
659         * @param str
660         * @return return if a String is "Empty", that means NULL or String with length 0 (whitespaces will not counted) 
661         */
662        public static boolean isEmpty(String str) {
663            return str==null || str.length()==0;
664        }
665        /**
666         * 
667         * @param str
668         * @return return if a String is "Empty", that means NULL or String with length 0 (whitespaces will not counted) 
669         */
670        public static boolean isEmpty(String str, boolean trim) {
671            if(!trim) return isEmpty(str);
672            return str==null || str.trim().length()==0;
673        }
674        
675        /**
676         * return the first character of a string, if string ist empty return 0;
677         * @param str string to get first character
678         * @return first character
679         */
680        public static char firstChar(String str) {
681            if(isEmpty(str)) return 0;
682            return str.charAt(0);
683        }
684    
685            /**
686             * change charset of string from system default to givenstr
687             * @param str
688             * @param charset
689             * @return
690             * @throws UnsupportedEncodingException 
691             */
692            public static String changeCharset(String str, String charset) throws UnsupportedEncodingException {
693                    if(str==null) return str;
694                    return new String(str.getBytes(charset),charset);
695            }
696    
697            /**
698             * change charset of string from system default to givenstr
699             * @param str
700             * @param charset
701             * @return
702             * @throws UnsupportedEncodingException 
703             */
704            public static String changeCharset(String str, String charset, String defaultValue) {
705                    if(str==null) return str;
706                    try {
707                            return new String(str.getBytes(SystemUtil.getCharset()),charset);
708                    } catch (UnsupportedEncodingException e) {
709                            return defaultValue;
710                    }
711            }
712    
713            public static boolean isWhiteSpace(char c) {
714                    return c<=' ';
715            }
716    
717            public static String removeWhiteSpace(String str) {
718                    if(isEmpty(str)) return str;
719                    StringBuilder sb=new StringBuilder();
720                    char[] carr = str.trim().toCharArray();
721                    for(int i=0;i<carr.length;i++) {
722                            if(!isWhiteSpace(carr[i]))sb.append(carr[i]);
723                    }
724                    return sb.toString();
725            }
726    
727            public static String replaceLast(String str, char from, char to) {
728                    int index = str.lastIndexOf(from);
729                    if(index==-1)return str;
730                    return str.substring(0,index)+to+str.substring(index+1);
731            }
732            public static String replaceLast(String str, String from, String to) {
733                    int index = str.lastIndexOf(from);
734                    if(index==-1)return str;
735                    return str.substring(0,index)+to+str.substring(index+from.length());
736            }
737    
738            /**
739             * removes quotes(",') that wraps the string
740             * @param string
741             * @return
742             */
743            public static String removeQuotes(String string,boolean trim) {
744                    if(trim)string=string.trim();
745                    if((StringUtil.startsWith(string, '"') && StringUtil.endsWith(string, '"')) || (StringUtil.startsWith(string, '\'') && StringUtil.endsWith(string, '\''))){
746                            string= string.substring(1,string.length()-1);
747                            if(trim)string=string.trim();
748                    }
749                    return string;
750            }
751    
752            public static boolean isEmpty(Object obj, boolean trim) {
753                    if(obj==null) return true;
754                    if(obj instanceof String)return isEmpty((String)obj,trim);
755                    if(obj instanceof StringBuffer)return isEmpty((StringBuffer)obj,trim);
756                    if(obj instanceof StringBuilder)return isEmpty((StringBuilder)obj,trim);
757                    if(obj instanceof Collection.Key)return isEmpty(((Collection.Key)obj).getString(),trim);
758                    return false;
759            }
760            
761            public static boolean isEmpty(Object obj) {
762                    if(obj==null) return true;
763                    if(obj instanceof String)return isEmpty((String)obj);
764                    if(obj instanceof Collection.Key)return isEmpty(((Collection.Key)obj).getString());
765                    if(obj instanceof StringBuffer)return isEmpty((StringBuffer)obj);
766                    if(obj instanceof StringBuilder)return isEmpty((StringBuilder)obj);
767                    return false;
768            }
769    
770            public static boolean isEmpty(StringBuffer sb,boolean trim) {
771                    if(trim) return sb==null || sb.toString().trim().length()==0;
772                    return sb==null || sb.length()==0;
773            }
774            public static boolean isEmpty(StringBuilder sb,boolean trim) {
775                    if(trim) return sb==null || sb.toString().trim().length()==0;
776                    return sb==null || sb.length()==0;
777            }
778    
779            public static boolean isEmpty(StringBuffer sb) {
780                    return sb==null || sb.length()==0;
781            }
782    
783            public static boolean isEmpty(StringBuilder sb) {
784                    return sb==null || sb.length()==0;
785            }
786    
787            public static String removeStarting(String str, String sub) {
788                    if(isEmpty(str) || isEmpty(sub) || !str.startsWith(sub)) return str;
789                    return str.substring(sub.length());
790            }
791    
792            public static String removeStartingIgnoreCase(String str, String sub) {
793                    if(isEmpty(sub) || !startsWithIgnoreCase(str, sub)) return str;
794                    return str.substring(sub.length());
795            }
796    
797            
798            public static String[] merge(String str, String[] arr) {
799                    String[] narr=new String[arr.length+1];
800            narr[0]=str;
801            for(int i=0;i<arr.length;i++) {
802                    narr[i+1]=arr[i];
803            }
804            return narr;
805            
806            }
807    
808            public static int length(String str) {
809                    if(str==null) return 0;
810                    return str.length();
811            }
812    
813            public static boolean hasUpperCase(String str) {
814                    if(isEmpty(str)) return false;
815                    return !str.equals(str.toLowerCase());
816            }
817    
818            /**
819             * trim given value, return defaultvalue when input is null
820             * @param string
821             * @param defaultValue
822             * @return trimmed string or defaultValue
823             */
824            public static String trim(String str,String defaultValue) {
825                    if(str==null) return defaultValue;
826                    return str.trim();
827            }
828    
829            public static boolean contains(String str, String substr) {
830                    if(str==null) return false;
831                    return str.indexOf(substr)!=-1;
832            }
833    
834            public static boolean containsIgnoreCase(String str, String substr) {
835                    return indexOfIgnoreCase(str,substr)!=-1;
836            }
837    
838            public static String substringEL(String str, int index,String defaultValue) {
839                    if(str==null || index<0 || index>str.length()) return defaultValue;
840                    return str.substring(index);
841            }
842    
843            /**
844             * translate a string in camel notation to a string in hypen notation
845             * example:
846             * helloWorld -> hello-world
847             * @param str
848             * @return
849             */
850            public static String camelToHypenNotation(String str) {
851                    if(isEmpty(str)) return str;
852                    
853                    StringBuilder sb=new StringBuilder();
854                    int len=str.length();
855                    char c;
856                    
857                    sb.append(Character.toLowerCase(str.charAt(0)));
858                    for(int i=1;i<str.length();i++){
859                            c=str.charAt(i);
860                            if(Character.isUpperCase(c)){
861                                    sb.append('-');
862                                    sb.append(Character.toLowerCase(c));
863                            }
864                            else sb.append(c);
865                    }
866                    return sb.toString();
867            }
868    
869            /**
870             * translate a string in hypen notation to a string in camel notation
871             * example:
872             * hello-world -> helloWorld
873             * @param str
874             * @return
875             */
876            public static String hypenToCamelNotation(String str) {
877                    if(isEmpty(str)) return str;
878                    
879                    StringBuilder sb=new StringBuilder();
880                    int len=str.length();
881                    char c;
882                    
883                    for(int i=0;i<str.length();i++){
884                            c=str.charAt(i);
885                            if(c=='-'){
886                                    if(len>++i) sb.append(Character.toUpperCase(str.charAt(i)));
887                            }
888                            else sb.append(c);
889                    }
890                    return sb.toString();
891            }
892    
893            public static boolean isAscci(String str) {
894                    char c;
895                    for(int i=str.length()-1;i>=0;i--){
896                            c = str.charAt(i);
897                            if(c < 128)  continue;
898                            return false;
899                    }
900                    return true;
901            }
902    }