001 /* 002 Copyright (C) 2001-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.util; 019 020 import java.io.File; 021 import java.util.Collection; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Vector; 026 027 /** 028 * Various often used string functions 029 */ 030 public class Strings 031 { 032 /** 033 * Replace slashed characters ("\t" -> '\t',"\r" -> '\t', 034 * "\n" -> '\n' ,"\f" -> '\f' , "\_" -> ' ') 035 */ 036 public static String unslashify (String str) { 037 StringBuffer ret = new StringBuffer(str.length()); 038 int i=0; 039 while(i<str.length()) { 040 char c = str.charAt(i++); 041 if (c == '\\') { 042 c = str.charAt(i++); 043 switch (c) { 044 case 't': c='\t'; break; 045 case 'r': c='\r'; break; 046 case 'n': c='\n'; break; 047 case 'f': c='\f'; break; 048 case '_': c=' '; break; 049 } 050 } 051 ret.append(c); 052 } 053 return ret.toString(); 054 } 055 056 /** 057 * The reverse of unslashify. slashify(unslashify(str)).equals(str). 058 */ 059 public static String slashify(String str) { 060 StringBuffer ret = new StringBuffer((int)(str.length()*1.2)); 061 for(int i=0; i<str.length(); i++) { 062 char c = str.charAt(i); 063 switch (c) { 064 case '\\': ret.append("\\\\"); break; 065 case '\t': ret.append("\\t"); break; 066 case '\r': ret.append("\\r"); break; 067 case '\n': ret.append("\\n"); break; 068 case '\f': ret.append("\\f"); break; 069 case ' ': ret.append("\\_"); break; 070 default: ret.append(c); break; 071 } 072 } 073 return ret.toString(); 074 } 075 076 /** 077 * Split a string into an array 078 * @param source string to split 079 * @param separator the separator 080 * @return an array of strings 081 * @see #splitToList(String,String) 082 */ 083 public static String[] split(String source, String separator) { 084 return (String[])splitToList(source,separator).toArray(ExtArrays.emptyStringArray); 085 } 086 087 /** 088 * Split a string into a list of strings 089 * @param source string to split 090 * @param separator the separator 091 * @return a list of strings 092 * @see #split(String,String) 093 */ 094 public static List splitToList(String source, String separator) { 095 Vector tmp = new Vector(); 096 int startIndex =0; 097 int index = 0; 098 while ((index = source.indexOf(separator,startIndex))!=-1) { 099 tmp.add(source.substring(startIndex,index)); 100 startIndex = index+separator.length(); 101 } 102 if (source.length()>0 && startIndex<source.length()) 103 tmp.add(source.substring(startIndex)); 104 return tmp; 105 } 106 107 /** 108 * Builds a string formed by the toString() of items from a 109 * collection separated by a separator string. 110 * @param items the collection. It must not contain null values 111 * @param separator the separator string 112 * @see #join(String[],String) 113 */ 114 public static String join(Collection items, String separator) { 115 StringBuffer result = new StringBuffer(); 116 Iterator it = items.iterator(); 117 while (it.hasNext()) { 118 result.append(it.next().toString()); 119 if (it.hasNext()) 120 result.append(separator); 121 } 122 return result.toString(); 123 } 124 125 /** 126 * Builds a string formed by the toString() of items from a 127 * collection separated by a separator string. 128 * @param items the collection. It may contain null values. 129 * @param separator the separator string 130 * @see #join(String[],String) 131 */ 132 public static String safeJoin(Collection items, String separator) { 133 StringBuffer result = new StringBuffer(); 134 Iterator it = items.iterator(); 135 while (it.hasNext()) { 136 Object o = it.next(); 137 result.append(o!=null?o.toString():"#NULL#"); 138 if (it.hasNext()) 139 result.append(separator); 140 } 141 return result.toString(); 142 } 143 144 /** 145 * @see #join(Collection,String) 146 */ 147 public static String join(String[] items, String separator) { 148 StringBuffer result = new StringBuffer(); 149 for (int i=0; i<items.length; i++) { 150 if (i>0) 151 result.append(separator); 152 result.append(items[i]); 153 } 154 return result.toString(); 155 } 156 157 /** 158 * Split a list of paths separated by path.separator 159 * 160 * @return an array of path 161 */ 162 public static String[] splitPath(String paths) { 163 return Strings.split(paths,System.getProperty("path.separator")); 164 } 165 166 /** 167 * Create a path string, using the appropriate path separator 168 * @param paths a collection of File 169 * @return the filenames of paths, separated by the appropriate path separator 170 */ 171 public static String createPathString(Collection paths) { 172 String separator = System.getProperty("path.separator"); 173 String pathString = null; 174 Iterator it = paths.iterator(); 175 while (it.hasNext()) { 176 File path = (File)it.next(); 177 if (pathString==null) 178 pathString = path.toString(); 179 else 180 pathString += separator+path.toString(); 181 } 182 return pathString; 183 } 184 185 /** 186 * Build a String representation of an object of the form 187 * <classname>@<hashcode> 188 * @param o the object to stringify 189 * @return a String representation of the object 190 */ 191 public static String hex(Object o) { 192 return o==null?"null":o.getClass().getName()+"@"+Integer.toHexString(o.hashCode()); 193 } 194 195 public static String hash(Object o) { 196 return o==null?"null":"@"+Integer.toHexString(o.hashCode()); 197 } 198 199 /** 200 * Build a String representation of a vector in the way as 201 * Vector.toString(), but without brackets. 202 * @param list the vector to stringify 203 * @return a String representation of the vector 204 */ 205 public static String toString(Collection list) { 206 StringBuffer buffer = new StringBuffer(); 207 buffer.append("["); 208 209 Iterator i = list.iterator(); 210 while (i.hasNext()) { 211 Object item = i.next(); 212 buffer.append(item==null ? "null" : item.toString()); 213 if (i.hasNext()) 214 buffer.append(", "); 215 } 216 217 buffer.append("]"); 218 return buffer.toString(); 219 } 220 221 public static String toString(Map map) { 222 StringBuffer buffer = new StringBuffer(); 223 buffer.append("{"); 224 225 Iterator i = map.entrySet().iterator(); 226 while (i.hasNext()) { 227 Map.Entry entry = (Map.Entry)i.next(); 228 buffer.append(String.valueOf(entry.getKey())); 229 buffer.append("="); 230 buffer.append(String.valueOf(entry.getValue())); 231 if (i.hasNext()) 232 buffer.append(", "); 233 } 234 235 buffer.append("}"); 236 return buffer.toString(); 237 } 238 239 /** 240 * Build a string with a given length and all the characters 241 * equals. 242 * @param c the character to fill the string with 243 * @param length the length of the string 244 * @return a string with the required length where 245 * string.charAt(i)==c for all i between 0 and lenght-1. 246 */ 247 public static String newString(char c, int length) { 248 char[] array = new char[length]; 249 for (length--;length>=0;length--) { 250 array[length] = c; 251 } 252 return new String(array); 253 } 254 255 /** 256 * A useful method that replaces all the occurences of a string. 257 * 258 * @param orgString the original string 259 * @param oldString the string to replace (if found) in the 260 * original string 261 * @param newString the string that replaces all the occurences of 262 * old string 263 * @return a new string with the occurences replaced 264 */ 265 public static String replace(String orgString, 266 String oldString, String newString) { 267 268 int pos = 0; 269 boolean end = false; 270 271 StringBuffer result = new StringBuffer(orgString.length()*2); 272 273 int oldLen = oldString.length(); 274 while (!end) { 275 int newpos = orgString.indexOf(oldString,pos); 276 if (newpos != -1) { 277 result.append(orgString.substring(pos, newpos)); 278 result.append(newString); 279 } else { 280 result.append(orgString.substring(pos)); 281 end = true; 282 } 283 pos = newpos + oldLen; 284 } 285 return result.toString(); 286 } 287 288 /** 289 * Replaces all occurences of some characters by a character 290 * @param oldChars the characters that should be replaced 291 * @param newChar the character by which to replace 292 * @param s the string buffer whose's characters must be replaced 293 */ 294 public static void replace(String oldChars, char newChar, StringBuffer s) { 295 for (int i=0; i<s.length(); i++) { 296 if (oldChars.indexOf(s.charAt(i))!=-1) 297 s.setCharAt(i,newChar); 298 } 299 } 300 301 /** 302 * Replaces all occurences of some characters by a character 303 * @param oldChars the characters that should be replaced 304 * @param newChar the character by which to replace 305 * @param s the string whose's characters must be replaced 306 */ 307 public static String replace(String oldChars, char newChar, String s) { 308 StringBuffer result = new StringBuffer(s); 309 replace(oldChars,newChar,result); 310 return result.toString(); 311 } 312 313 /** 314 * Delete occurences of characters from a StringBuffer 315 * @param delChars the characters to delete 316 * @param s the StringBuffer to remlove the characters from 317 */ 318 public static void deleteChars(String delChars, StringBuffer s) { 319 int length = s.length(); 320 int current = 0; 321 for (int i=0; i<length; i++) { 322 char c = s.charAt(i); 323 if (delChars.indexOf(c)==-1) { 324 s.setCharAt(current,c); 325 current++; 326 } 327 } 328 s.setLength(current); 329 } 330 331 public static String getShortClassName(Class cl) { 332 String type = cl.getName(); 333 if (cl.isArray()) { 334 type = cl.getComponentType().getName(); 335 } 336 type = type.substring(type.lastIndexOf( '.' )+1); 337 if (cl.isArray()) { 338 type = type + "[]"; 339 } 340 return type; 341 } 342 343 public static String getShortClassName(String className) { 344 return className.substring(className.lastIndexOf( '.' )+1); 345 } 346 347 public static String toUSAscii(String s) { 348 StringBuffer result = new StringBuffer(s); 349 toUSAscii(result); 350 return result.toString(); 351 } 352 353 /** 354 * Lowers all characters of a StringBuffer 355 */ 356 public static void toLowerCase(StringBuffer s) { 357 for (int i=0; i<s.length(); i++) { 358 s.setCharAt(i,Character.toLowerCase(s.charAt(i))); 359 } 360 } 361 362 /** 363 * Uppers all characters of a StringBuffer 364 */ 365 public static void toUpperCase(StringBuffer s) { 366 for (int i=0; i<s.length(); i++) { 367 s.setCharAt(i,Character.toUpperCase(s.charAt(i))); 368 } 369 } 370 371 /** 372 * Replace accented chars with their non-accented value. For 373 * instance, 'é' becomes 'e'. 374 * @param s string to convert 375 * @return converted string 376 */ 377 public static void toUSAscii(StringBuffer s) { 378 for (int i=s.length()-1; i>=0; i--) { 379 switch (s.charAt(i)) { 380 case 'é': 381 case 'è': 382 case 'ê': 383 case 'ë': 384 s.setCharAt(i, 'e'); 385 break; 386 case 'É': 387 case 'È': 388 case 'Ê': 389 case 'Ë': 390 s.setCharAt(i, 'E'); 391 break; 392 case 'ï': 393 case 'î': 394 case 'ì': 395 case 'Ã': 396 s.setCharAt(i, 'i'); 397 break; 398 case 'Ã?': 399 case 'ÃŽ': 400 case 'ÃŒ': 401 case 'Ã?': 402 s.setCharAt(i, 'I'); 403 break; 404 case 'à ': 405 case 'â': 406 case 'ä': 407 case 'ã': 408 case 'Ã¥': 409 s.setCharAt(i, 'a'); 410 break; 411 case 'À': 412 case 'Â': 413 case 'Ä': 414 case 'Ã': 415 case 'Ã…': 416 s.setCharAt(i, 'A'); 417 break; 418 case 'ù': 419 case 'ú': 420 case 'ü': 421 case 'û': 422 s.setCharAt(i, 'u'); 423 break; 424 case 'Ù': 425 case 'Ú': 426 case 'Ü': 427 case 'Û': 428 s.setCharAt(i, 'U'); 429 break; 430 case 'ö': 431 case 'ô': 432 case 'ó': 433 case 'ò': 434 case 'õ': 435 s.setCharAt(i, 'o'); 436 break; 437 case 'Ö': 438 case 'Ô': 439 case 'Ó': 440 case 'Ã’': 441 case 'Õ': 442 s.setCharAt(i, 'O'); 443 break; 444 case 'ç': 445 s.setCharAt(i, 'c'); 446 break; 447 case 'Ç': 448 s.setCharAt(i, 'C'); 449 break; 450 case 'ÿ': 451 case 'ý': 452 s.setCharAt(i, 'y'); 453 break; 454 case 'Ã?': 455 s.setCharAt(i, 'Y'); 456 break; 457 case 'ñ': 458 s.setCharAt(i, 'n'); 459 break; 460 case 'Ñ': 461 s.setCharAt(i, 'N'); 462 break; 463 default: 464 } 465 } 466 } 467 468 /** 469 * Compares the USAscii representation of two strings in a case insensitive manner. 470 * @param a first string to compare 471 * @param b second string to compare 472 * @return true if a and b are equals 473 */ 474 public static boolean equalsUSAsciiNoCase(String a, String b) { 475 if (a==null) 476 return b==null; 477 else if (b==null) 478 return a==null; 479 else 480 return toUSAscii(a).toLowerCase().equals(toUSAscii(b).toLowerCase()); 481 } 482 483 /** 484 * Tells if a string is empty (is null, has a zero length, or 485 * contains only whitespaces) 486 * @param str string to test 487 * @return true if str is null, str.length()==0 or str.trim().length()==0 488 */ 489 public static boolean isEmpty(String str) { 490 return str==null || str.length()==0 || str.trim().length()==0; 491 } 492 493 /** 494 * Removes all whitespace and CR/LF characters at the beginning or 495 * at the end of a string. 496 * @param str the string to trim 497 */ 498 public static String trimWSAndCRLF(String str) { 499 if (str==null || str.length()==0) 500 return str; 501 502 // Trim at the beginning 503 int start = 0; 504 char c = str.charAt(start); 505 while (Character.isWhitespace(c) || c=='\n' || c=='\r') { 506 start++; 507 if (start>=str.length()) 508 break; 509 c = str.charAt(start); 510 } 511 512 // Trim at the end 513 int end = str.length()-1; 514 c = str.charAt(end); 515 while (end>=start && (Character.isWhitespace(c) || c=='\n' || c=='\r')) { 516 end--; 517 c = str.charAt(end); 518 } 519 if (end<start) 520 return ""; 521 else 522 return str.substring(start,end+1); 523 } 524 525 526 /** 527 * Convert a String to a string with onlu iso-8859-1 528 * characters. Non iso-8859-1 characters are encoded with \\u<char_value> 529 * @param s strng to encode 530 * @see #fromISO8859_1(String) 531 */ 532 public static String toISO8599_1(String s) { 533 int len = s.length(); 534 StringBuffer res = new StringBuffer(len*2); 535 536 for(int i=0; i<len; i++) { 537 char c = s.charAt(i); 538 if (c=='\\') 539 res.append("\\\\"); 540 else if ((c < 0x0020) || (c > 0x007e)) { 541 switch (c) { 542 case 'é': case 'è': case 'ê': case 'ë': 543 case 'É': case 'È': case 'Ê': case 'Ë': 544 case 'ï': case 'î': case 'ì': case 'Ã': 545 case 'Ã?': case 'ÃŽ': case 'ÃŒ': case 'Ã?': 546 case 'à ': case 'â': case 'ä': case 'ã': case 'Ã¥': 547 case 'À': case 'Â': case 'Ä': case 'Ã': case 'Ã…': 548 case 'ù': case 'ú': case 'ü': case 'û': 549 case 'Ù': case 'Ú': case 'Ü': case 'Û': 550 case 'ö': case 'ô': case 'ó': case 'ò': case 'õ': 551 case 'Ö': case 'Ô': case 'Ó': case 'Ã’': case 'Õ': 552 case 'ç': case 'Ç': 553 case 'ÿ': case 'ý': case 'Ã?': 554 case 'ñ': case 'Ñ': 555 case '\n': case '\t': case '\r': 556 res.append(c); 557 break; 558 default: 559 res.append("\\u"); 560 res.append(hexDigit[(c >> 12) & 0xF]); 561 res.append(hexDigit[(c >> 8) & 0xF]); 562 res.append(hexDigit[(c >> 4) & 0xF]); 563 res.append(hexDigit[c & 0xF]); 564 } 565 } else { 566 res.append(c); 567 } 568 } 569 return res.toString(); 570 } 571 572 /** 573 * Convert a String to a string with onlu iso-8859-1 574 * characters. Non iso-8859-1 characters are encoded with \\u<char_value> 575 * @param s string to decode 576 * @see #fromISO8859_1(String) 577 */ 578 public static String fromISO8859_1(String s) { 579 char c; 580 int len = s.length(); 581 StringBuffer res = new StringBuffer(len); 582 583 int i=0; 584 while (i<len) { 585 c = s.charAt(i++); 586 if (c == '\\') { 587 c = s.charAt(i++); 588 if (c == 'u') { 589 // Read the xxxx 590 int value=0; 591 for (int j=0; j<4; j++) { 592 c = s.charAt(i++); 593 switch (c) { 594 case '0': case '1': case '2': case '3': case '4': 595 case '5': case '6': case '7': case '8': case '9': 596 value = (value << 4) + c - '0'; 597 break; 598 case 'a': case 'b': case 'c': 599 case 'd': case 'e': case 'f': 600 value = (value << 4) + 10 + c - 'a'; 601 break; 602 case 'A': case 'B': case 'C': 603 case 'D': case 'E': case 'F': 604 value = (value << 4) + 10 + c - 'A'; 605 break; 606 default: 607 throw new IllegalArgumentException( 608 "Malformed \\uxxxx encoding."); 609 } 610 } 611 res.append((char)value); 612 } else { 613 res.append(c); 614 } 615 } else { 616 res.append(c); 617 } 618 } 619 return res.toString(); 620 } 621 622 private static final char[] hexDigit = { 623 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 624 }; 625 626 }