GNU Classpath (0.18) | ||
Frames | No Frames |
1: /* String.java -- immutable character sequences; the object of string literals 2: Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.lang; 41: 42: import gnu.java.lang.CharData; 43: 44: import java.io.Serializable; 45: import java.io.UnsupportedEncodingException; 46: import java.nio.ByteBuffer; 47: import java.nio.CharBuffer; 48: import java.nio.charset.CharacterCodingException; 49: import java.nio.charset.Charset; 50: import java.nio.charset.CharsetDecoder; 51: import java.nio.charset.CharsetEncoder; 52: import java.nio.charset.CodingErrorAction; 53: import java.nio.charset.IllegalCharsetNameException; 54: import java.nio.charset.UnsupportedCharsetException; 55: import java.text.Collator; 56: import java.util.Comparator; 57: import java.util.Locale; 58: import java.util.regex.Matcher; 59: import java.util.regex.Pattern; 60: import java.util.regex.PatternSyntaxException; 61: 62: /** 63: * Strings represent an immutable set of characters. All String literals 64: * are instances of this class, and two string literals with the same contents 65: * refer to the same String object. 66: * 67: * <p>This class also includes a number of methods for manipulating the 68: * contents of strings (of course, creating a new object if there are any 69: * changes, as String is immutable). Case mapping relies on Unicode 3.0.0 70: * standards, where some character sequences have a different number of 71: * characters in the uppercase version than the lower case. 72: * 73: * <p>Strings are special, in that they are the only object with an overloaded 74: * operator. When you use '+' with at least one String argument, both 75: * arguments have String conversion performed on them, and another String (not 76: * guaranteed to be unique) results. 77: * 78: * <p>String is special-cased when doing data serialization - rather than 79: * listing the fields of this class, a String object is converted to a string 80: * literal in the object stream. 81: * 82: * @author Paul N. Fisher 83: * @author Eric Blake (ebb9@email.byu.edu) 84: * @author Per Bothner (bothner@cygnus.com) 85: * @since 1.0 86: * @status updated to 1.4; but could use better data sharing via offset field 87: */ 88: public final class String implements Serializable, Comparable, CharSequence 89: { 90: // WARNING: String is a CORE class in the bootstrap cycle. See the comments 91: // in vm/reference/java/lang/Runtime for implications of this fact. 92: 93: /** 94: * This is probably not necessary because this class is special cased already 95: * but it will avoid showing up as a discrepancy when comparing SUIDs. 96: */ 97: private static final long serialVersionUID = -6849794470754667710L; 98: 99: /** 100: * Stores unicode multi-character uppercase expansion table. 101: * @see #toUpperCase(char) 102: * @see CharData#UPPER_EXPAND 103: */ 104: private static final char[] upperExpand 105: = zeroBasedStringValue(CharData.UPPER_EXPAND); 106: 107: /** 108: * Stores unicode multi-character uppercase special casing table. 109: * @see #upperCaseExpansion(char) 110: * @see CharData#UPPER_SPECIAL 111: */ 112: private static final char[] upperSpecial 113: = zeroBasedStringValue(CharData.UPPER_SPECIAL); 114: 115: /** 116: * Characters which make up the String. 117: * Package access is granted for use by StringBuffer. 118: */ 119: final char[] value; 120: 121: /** 122: * Holds the number of characters in value. This number is generally 123: * the same as value.length, but can be smaller because substrings and 124: * StringBuffers can share arrays. Package visible for use by trusted code. 125: */ 126: final int count; 127: 128: /** 129: * Caches the result of hashCode(). If this value is zero, the hashcode 130: * is considered uncached (even if 0 is the correct hash value). 131: */ 132: private int cachedHashCode; 133: 134: /** 135: * Holds the starting position for characters in value[]. Since 136: * substring()'s are common, the use of offset allows the operation 137: * to perform in O(1). Package access is granted for use by StringBuffer. 138: */ 139: final int offset; 140: 141: /** 142: * An implementation for {@link CASE_INSENSITIVE_ORDER}. 143: * This must be {@link Serializable}. The class name is dictated by 144: * compatibility with Sun's JDK. 145: */ 146: private static final class CaseInsensitiveComparator 147: implements Comparator, Serializable 148: { 149: /** 150: * Compatible with JDK 1.2. 151: */ 152: private static final long serialVersionUID = 8575799808933029326L; 153: 154: /** 155: * The default private constructor generates unnecessary overhead. 156: */ 157: CaseInsensitiveComparator() {} 158: 159: /** 160: * Compares to Strings, using 161: * <code>String.compareToIgnoreCase(String)</code>. 162: * 163: * @param o1 the first string 164: * @param o2 the second string 165: * @return < 0, 0, or > 0 depending on the case-insensitive 166: * comparison of the two strings. 167: * @throws NullPointerException if either argument is null 168: * @throws ClassCastException if either argument is not a String 169: * @see #compareToIgnoreCase(String) 170: */ 171: public int compare(Object o1, Object o2) 172: { 173: return ((String) o1).compareToIgnoreCase((String) o2); 174: } 175: } // class CaseInsensitiveComparator 176: 177: /** 178: * A Comparator that uses <code>String.compareToIgnoreCase(String)</code>. 179: * This comparator is {@link Serializable}. Note that it ignores Locale, 180: * for that, you want a Collator. 181: * 182: * @see Collator#compare(String, String) 183: * @since 1.2 184: */ 185: public static final Comparator CASE_INSENSITIVE_ORDER 186: = new CaseInsensitiveComparator(); 187: 188: /** 189: * Creates an empty String (length 0). Unless you really need a new object, 190: * consider using <code>""</code> instead. 191: */ 192: public String() 193: { 194: value = "".value; 195: offset = 0; 196: count = 0; 197: } 198: 199: /** 200: * Copies the contents of a String to a new String. Since Strings are 201: * immutable, only a shallow copy is performed. 202: * 203: * @param str String to copy 204: * @throws NullPointerException if value is null 205: */ 206: public String(String str) 207: { 208: value = str.value; 209: offset = str.offset; 210: count = str.count; 211: cachedHashCode = str.cachedHashCode; 212: } 213: 214: /** 215: * Creates a new String using the character sequence of the char array. 216: * Subsequent changes to data do not affect the String. 217: * 218: * @param data char array to copy 219: * @throws NullPointerException if data is null 220: */ 221: public String(char[] data) 222: { 223: this(data, 0, data.length, false); 224: } 225: 226: /** 227: * Creates a new String using the character sequence of a subarray of 228: * characters. The string starts at offset, and copies count chars. 229: * Subsequent changes to data do not affect the String. 230: * 231: * @param data char array to copy 232: * @param offset position (base 0) to start copying out of data 233: * @param count the number of characters from data to copy 234: * @throws NullPointerException if data is null 235: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 236: * || offset + count > data.length) 237: * (while unspecified, this is a StringIndexOutOfBoundsException) 238: */ 239: public String(char[] data, int offset, int count) 240: { 241: this(data, offset, count, false); 242: } 243: 244: /** 245: * Creates a new String using an 8-bit array of integer values, starting at 246: * an offset, and copying up to the count. Each character c, using 247: * corresponding byte b, is created in the new String as if by performing: 248: * 249: * <pre> 250: * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) 251: * </pre> 252: * 253: * @param ascii array of integer values 254: * @param hibyte top byte of each Unicode character 255: * @param offset position (base 0) to start copying out of ascii 256: * @param count the number of characters from ascii to copy 257: * @throws NullPointerException if ascii is null 258: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 259: * || offset + count > ascii.length) 260: * (while unspecified, this is a StringIndexOutOfBoundsException) 261: * @see #String(byte[]) 262: * @see #String(byte[], String) 263: * @see #String(byte[], int, int) 264: * @see #String(byte[], int, int, String) 265: * @deprecated use {@link #String(byte[], int, int, String)} to perform 266: * correct encoding 267: */ 268: public String(byte[] ascii, int hibyte, int offset, int count) 269: { 270: if (offset < 0 || count < 0 || offset + count > ascii.length) 271: throw new StringIndexOutOfBoundsException(); 272: value = new char[count]; 273: this.offset = 0; 274: this.count = count; 275: hibyte <<= 8; 276: offset += count; 277: while (--count >= 0) 278: value[count] = (char) (hibyte | (ascii[--offset] & 0xff)); 279: } 280: 281: /** 282: * Creates a new String using an 8-bit array of integer values. Each 283: * character c, using corresponding byte b, is created in the new String 284: * as if by performing: 285: * 286: * <pre> 287: * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) 288: * </pre> 289: * 290: * @param ascii array of integer values 291: * @param hibyte top byte of each Unicode character 292: * @throws NullPointerException if ascii is null 293: * @see #String(byte[]) 294: * @see #String(byte[], String) 295: * @see #String(byte[], int, int) 296: * @see #String(byte[], int, int, String) 297: * @see #String(byte[], int, int, int) 298: * @deprecated use {@link #String(byte[], String)} to perform 299: * correct encoding 300: */ 301: public String(byte[] ascii, int hibyte) 302: { 303: this(ascii, hibyte, 0, ascii.length); 304: } 305: 306: /** 307: * Creates a new String using the portion of the byte array starting at the 308: * offset and ending at offset + count. Uses the specified encoding type 309: * to decode the byte array, so the resulting string may be longer or 310: * shorter than the byte array. For more decoding control, use 311: * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, 312: * see {@link java.nio.charset.Charset}. The behavior is not specified if 313: * the decoder encounters invalid characters; this implementation throws 314: * an Error. 315: * 316: * @param data byte array to copy 317: * @param offset the offset to start at 318: * @param count the number of bytes in the array to use 319: * @param encoding the name of the encoding to use 320: * @throws NullPointerException if data or encoding is null 321: * @throws IndexOutOfBoundsException if offset or count is incorrect 322: * (while unspecified, this is a StringIndexOutOfBoundsException) 323: * @throws UnsupportedEncodingException if encoding is not found 324: * @throws Error if the decoding fails 325: * @since 1.1 326: */ 327: public String(byte[] data, int offset, int count, String encoding) 328: throws UnsupportedEncodingException 329: { 330: if (offset < 0 || count < 0 || offset + count > data.length) 331: throw new StringIndexOutOfBoundsException(); 332: try 333: { 334: CharsetDecoder csd = Charset.forName(encoding).newDecoder(); 335: csd.onMalformedInput(CodingErrorAction.REPLACE); 336: csd.onUnmappableCharacter(CodingErrorAction.REPLACE); 337: CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); 338: if(cbuf.hasArray()) 339: { 340: value = cbuf.array(); 341: this.offset = cbuf.position(); 342: this.count = cbuf.remaining(); 343: } else { 344: // Doubt this will happen. But just in case. 345: value = new char[cbuf.remaining()]; 346: cbuf.get(value); 347: this.offset = 0; 348: this.count = value.length; 349: } 350: } catch(CharacterCodingException e){ 351: throw new UnsupportedEncodingException("Encoding: "+encoding+ 352: " not found."); 353: } catch(IllegalCharsetNameException e){ 354: throw new UnsupportedEncodingException("Encoding: "+encoding+ 355: " not found."); 356: } catch(UnsupportedCharsetException e){ 357: throw new UnsupportedEncodingException("Encoding: "+encoding+ 358: " not found."); 359: } 360: } 361: 362: /** 363: * Creates a new String using the byte array. Uses the specified encoding 364: * type to decode the byte array, so the resulting string may be longer or 365: * shorter than the byte array. For more decoding control, use 366: * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, 367: * see {@link java.nio.charset.Charset}. The behavior is not specified if 368: * the decoder encounters invalid characters; this implementation throws 369: * an Error. 370: * 371: * @param data byte array to copy 372: * @param encoding the name of the encoding to use 373: * @throws NullPointerException if data or encoding is null 374: * @throws UnsupportedEncodingException if encoding is not found 375: * @throws Error if the decoding fails 376: * @see #String(byte[], int, int, String) 377: * @since 1.1 378: */ 379: public String(byte[] data, String encoding) 380: throws UnsupportedEncodingException 381: { 382: this(data, 0, data.length, encoding); 383: } 384: 385: /** 386: * Creates a new String using the portion of the byte array starting at the 387: * offset and ending at offset + count. Uses the encoding of the platform's 388: * default charset, so the resulting string may be longer or shorter than 389: * the byte array. For more decoding control, use 390: * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified 391: * if the decoder encounters invalid characters; this implementation throws 392: * an Error. 393: * 394: * @param data byte array to copy 395: * @param offset the offset to start at 396: * @param count the number of bytes in the array to use 397: * @throws NullPointerException if data is null 398: * @throws IndexOutOfBoundsException if offset or count is incorrect 399: * @throws Error if the decoding fails 400: * @see #String(byte[], int, int, String) 401: * @since 1.1 402: */ 403: public String(byte[] data, int offset, int count) 404: { 405: if (offset < 0 || count < 0 || offset + count > data.length) 406: throw new StringIndexOutOfBoundsException(); 407: int o, c; 408: char[] v; 409: String encoding; 410: try 411: { 412: encoding = System.getProperty("file.encoding"); 413: CharsetDecoder csd = Charset.forName(encoding).newDecoder(); 414: csd.onMalformedInput(CodingErrorAction.REPLACE); 415: csd.onUnmappableCharacter(CodingErrorAction.REPLACE); 416: CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); 417: if(cbuf.hasArray()) 418: { 419: v = cbuf.array(); 420: o = cbuf.position(); 421: c = cbuf.remaining(); 422: } else { 423: // Doubt this will happen. But just in case. 424: v = new char[cbuf.remaining()]; 425: cbuf.get(v); 426: o = 0; 427: c = v.length; 428: } 429: } catch(Exception ex){ 430: // If anything goes wrong (System property not set, 431: // NIO provider not available, etc) 432: // Default to the 'safe' encoding ISO8859_1 433: v = new char[count]; 434: o = 0; 435: c = count; 436: for (int i=0;i<count;i++) 437: v[i] = (char)data[offset+i]; 438: } 439: this.value = v; 440: this.offset = o; 441: this.count = c; 442: } 443: 444: /** 445: * Creates a new String using the byte array. Uses the encoding of the 446: * platform's default charset, so the resulting string may be longer or 447: * shorter than the byte array. For more decoding control, use 448: * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified 449: * if the decoder encounters invalid characters; this implementation throws 450: * an Error. 451: * 452: * @param data byte array to copy 453: * @throws NullPointerException if data is null 454: * @throws Error if the decoding fails 455: * @see #String(byte[], int, int) 456: * @see #String(byte[], int, int, String) 457: * @since 1.1 458: */ 459: public String(byte[] data) 460: { 461: this(data, 0, data.length); 462: } 463: 464: /** 465: * Creates a new String using the character sequence represented by 466: * the StringBuffer. Subsequent changes to buf do not affect the String. 467: * 468: * @param buffer StringBuffer to copy 469: * @throws NullPointerException if buffer is null 470: */ 471: public String(StringBuffer buffer) 472: { 473: synchronized (buffer) 474: { 475: offset = 0; 476: count = buffer.count; 477: // Share unless buffer is 3/4 empty. 478: if ((count << 2) < buffer.value.length) 479: { 480: value = new char[count]; 481: VMSystem.arraycopy(buffer.value, 0, value, 0, count); 482: } 483: else 484: { 485: buffer.shared = true; 486: value = buffer.value; 487: } 488: } 489: } 490: 491: /** 492: * Creates a new String using the character sequence represented by 493: * the StringBuilder. Subsequent changes to buf do not affect the String. 494: * 495: * @param buffer StringBuilder to copy 496: * @throws NullPointerException if buffer is null 497: */ 498: public String(StringBuilder buffer) 499: { 500: this(buffer.value, 0, buffer.count); 501: } 502: 503: /** 504: * Special constructor which can share an array when safe to do so. 505: * 506: * @param data the characters to copy 507: * @param offset the location to start from 508: * @param count the number of characters to use 509: * @param dont_copy true if the array is trusted, and need not be copied 510: * @throws NullPointerException if chars is null 511: * @throws StringIndexOutOfBoundsException if bounds check fails 512: */ 513: String(char[] data, int offset, int count, boolean dont_copy) 514: { 515: if (offset < 0 || count < 0 || offset + count > data.length) 516: throw new StringIndexOutOfBoundsException(); 517: if (dont_copy) 518: { 519: value = data; 520: this.offset = offset; 521: } 522: else 523: { 524: value = new char[count]; 525: VMSystem.arraycopy(data, offset, value, 0, count); 526: this.offset = 0; 527: } 528: this.count = count; 529: } 530: 531: /** 532: * Returns the number of characters contained in this String. 533: * 534: * @return the length of this String 535: */ 536: public int length() 537: { 538: return count; 539: } 540: 541: /** 542: * Returns the character located at the specified index within this String. 543: * 544: * @param index position of character to return (base 0) 545: * @return character located at position index 546: * @throws IndexOutOfBoundsException if index < 0 || index >= length() 547: * (while unspecified, this is a StringIndexOutOfBoundsException) 548: */ 549: public char charAt(int index) 550: { 551: if (index < 0 || index >= count) 552: throw new StringIndexOutOfBoundsException(index); 553: return value[offset + index]; 554: } 555: 556: /** 557: * Copies characters from this String starting at a specified start index, 558: * ending at a specified stop index, to a character array starting at 559: * a specified destination begin index. 560: * 561: * @param srcBegin index to begin copying characters from this String 562: * @param srcEnd index after the last character to be copied from this String 563: * @param dst character array which this String is copied into 564: * @param dstBegin index to start writing characters into dst 565: * @throws NullPointerException if dst is null 566: * @throws IndexOutOfBoundsException if any indices are out of bounds 567: * (while unspecified, source problems cause a 568: * StringIndexOutOfBoundsException, and dst problems cause an 569: * ArrayIndexOutOfBoundsException) 570: */ 571: public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) 572: { 573: if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) 574: throw new StringIndexOutOfBoundsException(); 575: VMSystem.arraycopy(value, srcBegin + offset, 576: dst, dstBegin, srcEnd - srcBegin); 577: } 578: 579: /** 580: * Copies the low byte of each character from this String starting at a 581: * specified start index, ending at a specified stop index, to a byte array 582: * starting at a specified destination begin index. 583: * 584: * @param srcBegin index to being copying characters from this String 585: * @param srcEnd index after the last character to be copied from this String 586: * @param dst byte array which each low byte of this String is copied into 587: * @param dstBegin index to start writing characters into dst 588: * @throws NullPointerException if dst is null and copy length is non-zero 589: * @throws IndexOutOfBoundsException if any indices are out of bounds 590: * (while unspecified, source problems cause a 591: * StringIndexOutOfBoundsException, and dst problems cause an 592: * ArrayIndexOutOfBoundsException) 593: * @see #getBytes() 594: * @see #getBytes(String) 595: * @deprecated use {@link #getBytes()}, which uses a char to byte encoder 596: */ 597: public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) 598: { 599: if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) 600: throw new StringIndexOutOfBoundsException(); 601: int i = srcEnd - srcBegin; 602: srcBegin += offset; 603: while (--i >= 0) 604: dst[dstBegin++] = (byte) value[srcBegin++]; 605: } 606: 607: /** 608: * Converts the Unicode characters in this String to a byte array. Uses the 609: * specified encoding method, so the result may be longer or shorter than 610: * the String. For more encoding control, use 611: * {@link java.nio.charset.CharsetEncoder}, and for valid character sets, 612: * see {@link java.nio.charset.Charset}. Unsupported characters get 613: * replaced by an encoding specific byte. 614: * 615: * @param enc encoding name 616: * @return the resulting byte array 617: * @throws NullPointerException if enc is null 618: * @throws UnsupportedEncodingException if encoding is not supported 619: * @since 1.1 620: */ 621: public byte[] getBytes(String enc) throws UnsupportedEncodingException 622: { 623: try 624: { 625: CharsetEncoder cse = Charset.forName(enc).newEncoder(); 626: cse.onMalformedInput(CodingErrorAction.REPLACE); 627: cse.onUnmappableCharacter(CodingErrorAction.REPLACE); 628: ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count)); 629: if(bbuf.hasArray()) 630: return bbuf.array(); 631: 632: // Doubt this will happen. But just in case. 633: byte[] bytes = new byte[bbuf.remaining()]; 634: bbuf.get(bytes); 635: return bytes; 636: 637: } catch(IllegalCharsetNameException e){ 638: throw new UnsupportedEncodingException("Encoding: "+enc+ 639: " not found."); 640: } catch(UnsupportedCharsetException e){ 641: throw new UnsupportedEncodingException("Encoding: "+enc+ 642: " not found."); 643: } catch(CharacterCodingException e){ 644: // XXX - Ignore coding exceptions? They shouldn't really happen. 645: return null; 646: } 647: } 648: 649: /** 650: * Converts the Unicode characters in this String to a byte array. Uses the 651: * encoding of the platform's default charset, so the result may be longer 652: * or shorter than the String. For more encoding control, use 653: * {@link java.nio.charset.CharsetEncoder}. Unsupported characters get 654: * replaced by an encoding specific byte. 655: * 656: * @return the resulting byte array, or null on a problem 657: * @since 1.1 658: */ 659: public byte[] getBytes() 660: { 661: try 662: { 663: return getBytes(System.getProperty("file.encoding")); 664: } catch(Exception e) { 665: // XXX - Throw an error here? 666: // For now, default to the 'safe' encoding. 667: byte[] bytes = new byte[count]; 668: for(int i=0;i<count;i++) 669: bytes[i] = (byte)((value[offset+i] <= 0xFF)? 670: value[offset+i]:'?'); 671: return bytes; 672: } 673: } 674: 675: /** 676: * Predicate which compares anObject to this. This is true only for Strings 677: * with the same character sequence. 678: * 679: * @param anObject the object to compare 680: * @return true if anObject is semantically equal to this 681: * @see #compareTo(String) 682: * @see #equalsIgnoreCase(String) 683: */ 684: public boolean equals(Object anObject) 685: { 686: if (! (anObject instanceof String)) 687: return false; 688: String str2 = (String) anObject; 689: if (count != str2.count) 690: return false; 691: if (value == str2.value && offset == str2.offset) 692: return true; 693: int i = count; 694: int x = offset; 695: int y = str2.offset; 696: while (--i >= 0) 697: if (value[x++] != str2.value[y++]) 698: return false; 699: return true; 700: } 701: 702: /** 703: * Compares the given StringBuffer to this String. This is true if the 704: * StringBuffer has the same content as this String at this moment. 705: * 706: * @param buffer the StringBuffer to compare to 707: * @return true if StringBuffer has the same character sequence 708: * @throws NullPointerException if the given StringBuffer is null 709: * @since 1.4 710: */ 711: public boolean contentEquals(StringBuffer buffer) 712: { 713: synchronized (buffer) 714: { 715: if (count != buffer.count) 716: return false; 717: if (value == buffer.value) 718: return true; // Possible if shared. 719: int i = count; 720: int x = offset + count; 721: while (--i >= 0) 722: if (value[--x] != buffer.value[i]) 723: return false; 724: return true; 725: } 726: } 727: 728: /** 729: * Compares a String to this String, ignoring case. This does not handle 730: * multi-character capitalization exceptions; instead the comparison is 731: * made on a character-by-character basis, and is true if:<br><ul> 732: * <li><code>c1 == c2</code></li> 733: * <li><code>Character.toUpperCase(c1) 734: * == Character.toUpperCase(c2)</code></li> 735: * <li><code>Character.toLowerCase(c1) 736: * == Character.toLowerCase(c2)</code></li> 737: * </ul> 738: * 739: * @param anotherString String to compare to this String 740: * @return true if anotherString is equal, ignoring case 741: * @see #equals(Object) 742: * @see Character#toUpperCase(char) 743: * @see Character#toLowerCase(char) 744: */ 745: public boolean equalsIgnoreCase(String anotherString) 746: { 747: if (anotherString == null || count != anotherString.count) 748: return false; 749: int i = count; 750: int x = offset; 751: int y = anotherString.offset; 752: while (--i >= 0) 753: { 754: char c1 = value[x++]; 755: char c2 = anotherString.value[y++]; 756: // Note that checking c1 != c2 is redundant, but avoids method calls. 757: if (c1 != c2 758: && Character.toUpperCase(c1) != Character.toUpperCase(c2) 759: && Character.toLowerCase(c1) != Character.toLowerCase(c2)) 760: return false; 761: } 762: return true; 763: } 764: 765: /** 766: * Compares this String and another String (case sensitive, 767: * lexicographically). The result is less than 0 if this string sorts 768: * before the other, 0 if they are equal, and greater than 0 otherwise. 769: * After any common starting sequence is skipped, the result is 770: * <code>this.charAt(k) - anotherString.charAt(k)</code> if both strings 771: * have characters remaining, or 772: * <code>this.length() - anotherString.length()</code> if one string is 773: * a subsequence of the other. 774: * 775: * @param anotherString the String to compare against 776: * @return the comparison 777: * @throws NullPointerException if anotherString is null 778: */ 779: public int compareTo(String anotherString) 780: { 781: int i = Math.min(count, anotherString.count); 782: int x = offset; 783: int y = anotherString.offset; 784: while (--i >= 0) 785: { 786: int result = value[x++] - anotherString.value[y++]; 787: if (result != 0) 788: return result; 789: } 790: return count - anotherString.count; 791: } 792: 793: /** 794: * Behaves like <code>compareTo(java.lang.String)</code> unless the Object 795: * is not a <code>String</code>. Then it throws a 796: * <code>ClassCastException</code>. 797: * 798: * @param o the object to compare against 799: * @return the comparison 800: * @throws NullPointerException if o is null 801: * @throws ClassCastException if o is not a <code>String</code> 802: * @since 1.2 803: */ 804: public int compareTo(Object o) 805: { 806: return compareTo((String) o); 807: } 808: 809: /** 810: * Compares this String and another String (case insensitive). This 811: * comparison is <em>similar</em> to equalsIgnoreCase, in that it ignores 812: * locale and multi-characater capitalization, and compares characters 813: * after performing 814: * <code>Character.toLowerCase(Character.toUpperCase(c))</code> on each 815: * character of the string. This is unsatisfactory for locale-based 816: * comparison, in which case you should use {@link java.text.Collator}. 817: * 818: * @param str the string to compare against 819: * @return the comparison 820: * @see Collator#compare(String, String) 821: * @since 1.2 822: */ 823: public int compareToIgnoreCase(String str) 824: { 825: int i = Math.min(count, str.count); 826: int x = offset; 827: int y = str.offset; 828: while (--i >= 0) 829: { 830: int result = Character.toLowerCase(Character.toUpperCase(value[x++])) 831: - Character.toLowerCase(Character.toUpperCase(str.value[y++])); 832: if (result != 0) 833: return result; 834: } 835: return count - str.count; 836: } 837: 838: /** 839: * Predicate which determines if this String matches another String 840: * starting at a specified offset for each String and continuing 841: * for a specified length. Indices out of bounds are harmless, and give 842: * a false result. 843: * 844: * @param toffset index to start comparison at for this String 845: * @param other String to compare region to this String 846: * @param ooffset index to start comparison at for other 847: * @param len number of characters to compare 848: * @return true if regions match (case sensitive) 849: * @throws NullPointerException if other is null 850: */ 851: public boolean regionMatches(int toffset, String other, int ooffset, int len) 852: { 853: return regionMatches(false, toffset, other, ooffset, len); 854: } 855: 856: /** 857: * Predicate which determines if this String matches another String 858: * starting at a specified offset for each String and continuing 859: * for a specified length, optionally ignoring case. Indices out of bounds 860: * are harmless, and give a false result. Case comparisons are based on 861: * <code>Character.toLowerCase()</code> and 862: * <code>Character.toUpperCase()</code>, not on multi-character 863: * capitalization expansions. 864: * 865: * @param ignoreCase true if case should be ignored in comparision 866: * @param toffset index to start comparison at for this String 867: * @param other String to compare region to this String 868: * @param ooffset index to start comparison at for other 869: * @param len number of characters to compare 870: * @return true if regions match, false otherwise 871: * @throws NullPointerException if other is null 872: */ 873: public boolean regionMatches(boolean ignoreCase, int toffset, 874: String other, int ooffset, int len) 875: { 876: if (toffset < 0 || ooffset < 0 || toffset + len > count 877: || ooffset + len > other.count) 878: return false; 879: toffset += offset; 880: ooffset += other.offset; 881: while (--len >= 0) 882: { 883: char c1 = value[toffset++]; 884: char c2 = other.value[ooffset++]; 885: // Note that checking c1 != c2 is redundant when ignoreCase is true, 886: // but it avoids method calls. 887: if (c1 != c2 888: && (! ignoreCase 889: || (Character.toLowerCase(c1) != Character.toLowerCase(c2) 890: && (Character.toUpperCase(c1) 891: != Character.toUpperCase(c2))))) 892: return false; 893: } 894: return true; 895: } 896: 897: /** 898: * Predicate which determines if this String contains the given prefix, 899: * beginning comparison at toffset. The result is false if toffset is 900: * negative or greater than this.length(), otherwise it is the same as 901: * <code>this.substring(toffset).startsWith(prefix)</code>. 902: * 903: * @param prefix String to compare 904: * @param toffset offset for this String where comparison starts 905: * @return true if this String starts with prefix 906: * @throws NullPointerException if prefix is null 907: * @see #regionMatches(boolean, int, String, int, int) 908: */ 909: public boolean startsWith(String prefix, int toffset) 910: { 911: return regionMatches(false, toffset, prefix, 0, prefix.count); 912: } 913: 914: /** 915: * Predicate which determines if this String starts with a given prefix. 916: * If the prefix is an empty String, true is returned. 917: * 918: * @param prefix String to compare 919: * @return true if this String starts with the prefix 920: * @throws NullPointerException if prefix is null 921: * @see #startsWith(String, int) 922: */ 923: public boolean startsWith(String prefix) 924: { 925: return regionMatches(false, 0, prefix, 0, prefix.count); 926: } 927: 928: /** 929: * Predicate which determines if this String ends with a given suffix. 930: * If the suffix is an empty String, true is returned. 931: * 932: * @param suffix String to compare 933: * @return true if this String ends with the suffix 934: * @throws NullPointerException if suffix is null 935: * @see #regionMatches(boolean, int, String, int, int) 936: */ 937: public boolean endsWith(String suffix) 938: { 939: return regionMatches(false, count - suffix.count, suffix, 0, suffix.count); 940: } 941: 942: /** 943: * Computes the hashcode for this String. This is done with int arithmetic, 944: * where ** represents exponentiation, by this formula:<br> 945: * <code>s[0]*31**(n-1) + s[1]*31**(n-2) + ... + s[n-1]</code>. 946: * 947: * @return hashcode value of this String 948: */ 949: public int hashCode() 950: { 951: if (cachedHashCode != 0) 952: return cachedHashCode; 953: 954: // Compute the hash code using a local variable to be reentrant. 955: int hashCode = 0; 956: int limit = count + offset; 957: for (int i = offset; i < limit; i++) 958: hashCode = hashCode * 31 + value[i]; 959: return cachedHashCode = hashCode; 960: } 961: 962: /** 963: * Finds the first instance of a character in this String. 964: * 965: * @param ch character to find 966: * @return location (base 0) of the character, or -1 if not found 967: */ 968: public int indexOf(int ch) 969: { 970: return indexOf(ch, 0); 971: } 972: 973: /** 974: * Finds the first instance of a character in this String, starting at 975: * a given index. If starting index is less than 0, the search 976: * starts at the beginning of this String. If the starting index 977: * is greater than the length of this String, -1 is returned. 978: * 979: * @param ch character to find 980: * @param fromIndex index to start the search 981: * @return location (base 0) of the character, or -1 if not found 982: */ 983: public int indexOf(int ch, int fromIndex) 984: { 985: if ((char) ch != ch) 986: return -1; 987: if (fromIndex < 0) 988: fromIndex = 0; 989: int i = fromIndex + offset; 990: for ( ; fromIndex < count; fromIndex++) 991: if (value[i++] == ch) 992: return fromIndex; 993: return -1; 994: } 995: 996: /** 997: * Finds the last instance of a character in this String. 998: * 999: * @param ch character to find 1000: * @return location (base 0) of the character, or -1 if not found 1001: */ 1002: public int lastIndexOf(int ch) 1003: { 1004: return lastIndexOf(ch, count - 1); 1005: } 1006: 1007: /** 1008: * Finds the last instance of a character in this String, starting at 1009: * a given index. If starting index is greater than the maximum valid 1010: * index, then the search begins at the end of this String. If the 1011: * starting index is less than zero, -1 is returned. 1012: * 1013: * @param ch character to find 1014: * @param fromIndex index to start the search 1015: * @return location (base 0) of the character, or -1 if not found 1016: */ 1017: public int lastIndexOf(int ch, int fromIndex) 1018: { 1019: if ((char) ch != ch) 1020: return -1; 1021: if (fromIndex >= count) 1022: fromIndex = count - 1; 1023: int i = fromIndex + offset; 1024: for ( ; fromIndex >= 0; fromIndex--) 1025: if (value[i--] == ch) 1026: return fromIndex; 1027: return -1; 1028: } 1029: 1030: /** 1031: * Finds the first instance of a String in this String. 1032: * 1033: * @param str String to find 1034: * @return location (base 0) of the String, or -1 if not found 1035: * @throws NullPointerException if str is null 1036: */ 1037: public int indexOf(String str) 1038: { 1039: return indexOf(str, 0); 1040: } 1041: 1042: /** 1043: * Finds the first instance of a String in this String, starting at 1044: * a given index. If starting index is less than 0, the search 1045: * starts at the beginning of this String. If the starting index 1046: * is greater than the length of this String, -1 is returned. 1047: * 1048: * @param str String to find 1049: * @param fromIndex index to start the search 1050: * @return location (base 0) of the String, or -1 if not found 1051: * @throws NullPointerException if str is null 1052: */ 1053: public int indexOf(String str, int fromIndex) 1054: { 1055: if (fromIndex < 0) 1056: fromIndex = 0; 1057: int limit = count - str.count; 1058: for ( ; fromIndex <= limit; fromIndex++) 1059: if (regionMatches(fromIndex, str, 0, str.count)) 1060: return fromIndex; 1061: return -1; 1062: } 1063: 1064: /** 1065: * Finds the last instance of a String in this String. 1066: * 1067: * @param str String to find 1068: * @return location (base 0) of the String, or -1 if not found 1069: * @throws NullPointerException if str is null 1070: */ 1071: public int lastIndexOf(String str) 1072: { 1073: return lastIndexOf(str, count - str.count); 1074: } 1075: 1076: /** 1077: * Finds the last instance of a String in this String, starting at 1078: * a given index. If starting index is greater than the maximum valid 1079: * index, then the search begins at the end of this String. If the 1080: * starting index is less than zero, -1 is returned. 1081: * 1082: * @param str String to find 1083: * @param fromIndex index to start the search 1084: * @return location (base 0) of the String, or -1 if not found 1085: * @throws NullPointerException if str is null 1086: */ 1087: public int lastIndexOf(String str, int fromIndex) 1088: { 1089: fromIndex = Math.min(fromIndex, count - str.count); 1090: for ( ; fromIndex >= 0; fromIndex--) 1091: if (regionMatches(fromIndex, str, 0, str.count)) 1092: return fromIndex; 1093: return -1; 1094: } 1095: 1096: /** 1097: * Creates a substring of this String, starting at a specified index 1098: * and ending at the end of this String. 1099: * 1100: * @param begin index to start substring (base 0) 1101: * @return new String which is a substring of this String 1102: * @throws IndexOutOfBoundsException if begin < 0 || begin > length() 1103: * (while unspecified, this is a StringIndexOutOfBoundsException) 1104: */ 1105: public String substring(int begin) 1106: { 1107: return substring(begin, count); 1108: } 1109: 1110: /** 1111: * Creates a substring of this String, starting at a specified index 1112: * and ending at one character before a specified index. 1113: * 1114: * @param beginIndex index to start substring (inclusive, base 0) 1115: * @param endIndex index to end at (exclusive) 1116: * @return new String which is a substring of this String 1117: * @throws IndexOutOfBoundsException if begin < 0 || end > length() 1118: * || begin > end (while unspecified, this is a 1119: * StringIndexOutOfBoundsException) 1120: */ 1121: public String substring(int beginIndex, int endIndex) 1122: { 1123: if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) 1124: throw new StringIndexOutOfBoundsException(); 1125: if (beginIndex == 0 && endIndex == count) 1126: return this; 1127: int len = endIndex - beginIndex; 1128: // Package constructor avoids an array copy. 1129: return new String(value, beginIndex + offset, len, 1130: (len << 2) >= value.length); 1131: } 1132: 1133: /** 1134: * Creates a substring of this String, starting at a specified index 1135: * and ending at one character before a specified index. This behaves like 1136: * <code>substring(begin, end)</code>. 1137: * 1138: * @param begin index to start substring (inclusive, base 0) 1139: * @param end index to end at (exclusive) 1140: * @return new String which is a substring of this String 1141: * @throws IndexOutOfBoundsException if begin < 0 || end > length() 1142: * || begin > end 1143: * @since 1.4 1144: */ 1145: public CharSequence subSequence(int begin, int end) 1146: { 1147: return substring(begin, end); 1148: } 1149: 1150: /** 1151: * Concatenates a String to this String. This results in a new string unless 1152: * one of the two originals is "". 1153: * 1154: * @param str String to append to this String 1155: * @return newly concatenated String 1156: * @throws NullPointerException if str is null 1157: */ 1158: public String concat(String str) 1159: { 1160: if (str.count == 0) 1161: return this; 1162: if (count == 0) 1163: return str; 1164: char[] newStr = new char[count + str.count]; 1165: VMSystem.arraycopy(value, offset, newStr, 0, count); 1166: VMSystem.arraycopy(str.value, str.offset, newStr, count, str.count); 1167: // Package constructor avoids an array copy. 1168: return new String(newStr, 0, newStr.length, true); 1169: } 1170: 1171: /** 1172: * Replaces every instance of a character in this String with a new 1173: * character. If no replacements occur, this is returned. 1174: * 1175: * @param oldChar the old character to replace 1176: * @param newChar the new character 1177: * @return new String with all instances of oldChar replaced with newChar 1178: */ 1179: public String replace(char oldChar, char newChar) 1180: { 1181: if (oldChar == newChar) 1182: return this; 1183: int i = count; 1184: int x = offset - 1; 1185: while (--i >= 0) 1186: if (value[++x] == oldChar) 1187: break; 1188: if (i < 0) 1189: return this; 1190: char[] newStr = (char[]) value.clone(); 1191: newStr[x] = newChar; 1192: while (--i >= 0) 1193: if (value[++x] == oldChar) 1194: newStr[x] = newChar; 1195: // Package constructor avoids an array copy. 1196: return new String(newStr, offset, count, true); 1197: } 1198: 1199: /** 1200: * Test if this String matches a regular expression. This is shorthand for 1201: * <code>{@link Pattern}.matches(regex, this)</code>. 1202: * 1203: * @param regex the pattern to match 1204: * @return true if the pattern matches 1205: * @throws NullPointerException if regex is null 1206: * @throws PatternSyntaxException if regex is invalid 1207: * @see Pattern#matches(String, CharSequence) 1208: * @since 1.4 1209: */ 1210: public boolean matches(String regex) 1211: { 1212: return Pattern.matches(regex, this); 1213: } 1214: 1215: /** 1216: * Replaces the first substring match of the regular expression with a 1217: * given replacement. This is shorthand for <code>{@link Pattern} 1218: * .compile(regex).matcher(this).replaceFirst(replacement)</code>. 1219: * 1220: * @param regex the pattern to match 1221: * @param replacement the replacement string 1222: * @return the modified string 1223: * @throws NullPointerException if regex or replacement is null 1224: * @throws PatternSyntaxException if regex is invalid 1225: * @see #replaceAll(String, String) 1226: * @see Pattern#compile(String) 1227: * @see Pattern#matcher(CharSequence) 1228: * @see Matcher#replaceFirst(String) 1229: * @since 1.4 1230: */ 1231: public String replaceFirst(String regex, String replacement) 1232: { 1233: return Pattern.compile(regex).matcher(this).replaceFirst(replacement); 1234: } 1235: 1236: /** 1237: * Replaces all matching substrings of the regular expression with a 1238: * given replacement. This is shorthand for <code>{@link Pattern} 1239: * .compile(regex).matcher(this).replaceAll(replacement)</code>. 1240: * 1241: * @param regex the pattern to match 1242: * @param replacement the replacement string 1243: * @return the modified string 1244: * @throws NullPointerException if regex or replacement is null 1245: * @throws PatternSyntaxException if regex is invalid 1246: * @see #replaceFirst(String, String) 1247: * @see Pattern#compile(String) 1248: * @see Pattern#matcher(CharSequence) 1249: * @see Matcher#replaceAll(String) 1250: * @since 1.4 1251: */ 1252: public String replaceAll(String regex, String replacement) 1253: { 1254: return Pattern.compile(regex).matcher(this).replaceAll(replacement); 1255: } 1256: 1257: /** 1258: * Split this string around the matches of a regular expression. Each 1259: * element of the returned array is the largest block of characters not 1260: * terminated by the regular expression, in the order the matches are found. 1261: * 1262: * <p>The limit affects the length of the array. If it is positive, the 1263: * array will contain at most n elements (n - 1 pattern matches). If 1264: * negative, the array length is unlimited, but there can be trailing empty 1265: * entries. if 0, the array length is unlimited, and trailing empty entries 1266: * are discarded. 1267: * 1268: * <p>For example, splitting "boo:and:foo" yields:<br> 1269: * <table border=0> 1270: * <th><td>Regex</td> <td>Limit</td> <td>Result</td></th> 1271: * <tr><td>":"</td> <td>2</td> <td>{ "boo", "and:foo" }</td></tr> 1272: * <tr><td>":"</td> <td>t</td> <td>{ "boo", "and", "foo" }</td></tr> 1273: * <tr><td>":"</td> <td>-2</td> <td>{ "boo", "and", "foo" }</td></tr> 1274: * <tr><td>"o"</td> <td>5</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> 1275: * <tr><td>"o"</td> <td>-2</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> 1276: * <tr><td>"o"</td> <td>0</td> <td>{ "b", "", ":and:f" }</td></tr> 1277: * </table> 1278: * 1279: * <p>This is shorthand for 1280: * <code>{@link Pattern}.compile(regex).split(this, limit)</code>. 1281: * 1282: * @param regex the pattern to match 1283: * @param limit the limit threshold 1284: * @return the array of split strings 1285: * @throws NullPointerException if regex or replacement is null 1286: * @throws PatternSyntaxException if regex is invalid 1287: * @see Pattern#compile(String) 1288: * @see Pattern#split(CharSequence, int) 1289: * @since 1.4 1290: */ 1291: public String[] split(String regex, int limit) 1292: { 1293: return Pattern.compile(regex).split(this, limit); 1294: } 1295: 1296: /** 1297: * Split this string around the matches of a regular expression. Each 1298: * element of the returned array is the largest block of characters not 1299: * terminated by the regular expression, in the order the matches are found. 1300: * The array length is unlimited, and trailing empty entries are discarded, 1301: * as though calling <code>split(regex, 0)</code>. 1302: * 1303: * @param regex the pattern to match 1304: * @return the array of split strings 1305: * @throws NullPointerException if regex or replacement is null 1306: * @throws PatternSyntaxException if regex is invalid 1307: * @see #split(String, int) 1308: * @see Pattern#compile(String) 1309: * @see Pattern#split(CharSequence, int) 1310: * @since 1.4 1311: */ 1312: public String[] split(String regex) 1313: { 1314: return Pattern.compile(regex).split(this, 0); 1315: } 1316: 1317: /** 1318: * Lowercases this String according to a particular locale. This uses 1319: * Unicode's special case mappings, as applied to the given Locale, so the 1320: * resulting string may be a different length. 1321: * 1322: * @param loc locale to use 1323: * @return new lowercased String, or this if no characters were lowercased 1324: * @throws NullPointerException if loc is null 1325: * @see #toUpperCase(Locale) 1326: * @since 1.1 1327: */ 1328: public String toLowerCase(Locale loc) 1329: { 1330: // First, see if the current string is already lower case. 1331: boolean turkish = "tr".equals(loc.getLanguage()); 1332: int i = count; 1333: int x = offset - 1; 1334: while (--i >= 0) 1335: { 1336: char ch = value[++x]; 1337: if ((turkish && ch == '\u0049') 1338: || ch != Character.toLowerCase(ch)) 1339: break; 1340: } 1341: if (i < 0) 1342: return this; 1343: 1344: // Now we perform the conversion. Fortunately, there are no multi-character 1345: // lowercase expansions in Unicode 3.0.0. 1346: char[] newStr = (char[]) value.clone(); 1347: do 1348: { 1349: char ch = value[x]; 1350: // Hardcoded special case. 1351: newStr[x++] = (turkish && ch == '\u0049') ? '\u0131' 1352: : Character.toLowerCase(ch); 1353: } 1354: while (--i >= 0); 1355: // Package constructor avoids an array copy. 1356: return new String(newStr, offset, count, true); 1357: } 1358: 1359: /** 1360: * Lowercases this String. This uses Unicode's special case mappings, as 1361: * applied to the platform's default Locale, so the resulting string may 1362: * be a different length. 1363: * 1364: * @return new lowercased String, or this if no characters were lowercased 1365: * @see #toLowerCase(Locale) 1366: * @see #toUpperCase() 1367: */ 1368: public String toLowerCase() 1369: { 1370: return toLowerCase(Locale.getDefault()); 1371: } 1372: 1373: /** 1374: * Uppercases this String according to a particular locale. This uses 1375: * Unicode's special case mappings, as applied to the given Locale, so the 1376: * resulting string may be a different length. 1377: * 1378: * @param loc locale to use 1379: * @return new uppercased String, or this if no characters were uppercased 1380: * @throws NullPointerException if loc is null 1381: * @see #toLowerCase(Locale) 1382: * @since 1.1 1383: */ 1384: public String toUpperCase(Locale loc) 1385: { 1386: // First, see how many characters we have to grow by, as well as if the 1387: // current string is already upper case. 1388: boolean turkish = "tr".equals(loc.getLanguage()); 1389: int expand = 0; 1390: boolean unchanged = true; 1391: int i = count; 1392: int x = i + offset; 1393: while (--i >= 0) 1394: { 1395: char ch = value[--x]; 1396: expand += upperCaseExpansion(ch); 1397: unchanged = (unchanged && expand == 0 1398: && ! (turkish && ch == '\u0069') 1399: && ch == Character.toUpperCase(ch)); 1400: } 1401: if (unchanged) 1402: return this; 1403: 1404: // Now we perform the conversion. 1405: i = count; 1406: if (expand == 0) 1407: { 1408: char[] newStr = (char[]) value.clone(); 1409: while (--i >= 0) 1410: { 1411: char ch = value[x]; 1412: // Hardcoded special case. 1413: newStr[x++] = (turkish && ch == '\u0069') ? '\u0130' 1414: : Character.toUpperCase(ch); 1415: } 1416: // Package constructor avoids an array copy. 1417: return new String(newStr, offset, count, true); 1418: } 1419: 1420: // Expansion is necessary. 1421: char[] newStr = new char[count + expand]; 1422: int j = 0; 1423: while (--i >= 0) 1424: { 1425: char ch = value[x++]; 1426: // Hardcoded special case. 1427: if (turkish && ch == '\u0069') 1428: { 1429: newStr[j++] = '\u0130'; 1430: continue; 1431: } 1432: expand = upperCaseExpansion(ch); 1433: if (expand > 0) 1434: { 1435: int index = upperCaseIndex(ch); 1436: while (expand-- >= 0) 1437: newStr[j++] = upperExpand[index++]; 1438: } 1439: else 1440: newStr[j++] = Character.toUpperCase(ch); 1441: } 1442: // Package constructor avoids an array copy. 1443: return new String(newStr, 0, newStr.length, true); 1444: } 1445: 1446: /** 1447: * Uppercases this String. This uses Unicode's special case mappings, as 1448: * applied to the platform's default Locale, so the resulting string may 1449: * be a different length. 1450: * 1451: * @return new uppercased String, or this if no characters were uppercased 1452: * @see #toUpperCase(Locale) 1453: * @see #toLowerCase() 1454: */ 1455: public String toUpperCase() 1456: { 1457: return toUpperCase(Locale.getDefault()); 1458: } 1459: 1460: /** 1461: * Trims all characters less than or equal to <code>'\u0020'</code> 1462: * (<code>' '</code>) from the beginning and end of this String. This 1463: * includes many, but not all, ASCII control characters, and all 1464: * {@link Character#isWhitespace(char)}. 1465: * 1466: * @return new trimmed String, or this if nothing trimmed 1467: */ 1468: public String trim() 1469: { 1470: int limit = count + offset; 1471: if (count == 0 || (value[offset] > '\u0020' 1472: && value[limit - 1] > '\u0020')) 1473: return this; 1474: int begin = offset; 1475: do 1476: if (begin == limit) 1477: return ""; 1478: while (value[begin++] <= '\u0020'); 1479: int end = limit; 1480: while (value[--end] <= '\u0020'); 1481: return substring(begin - offset - 1, end - offset + 1); 1482: } 1483: 1484: /** 1485: * Returns this, as it is already a String! 1486: * 1487: * @return this 1488: */ 1489: public String toString() 1490: { 1491: return this; 1492: } 1493: 1494: /** 1495: * Copies the contents of this String into a character array. Subsequent 1496: * changes to the array do not affect the String. 1497: * 1498: * @return character array copying the String 1499: */ 1500: public char[] toCharArray() 1501: { 1502: if (count == value.length) 1503: return (char[]) value.clone(); 1504: 1505: char[] copy = new char[count]; 1506: VMSystem.arraycopy(value, offset, copy, 0, count); 1507: return copy; 1508: } 1509: 1510: /** 1511: * Returns a String representation of an Object. This is "null" if the 1512: * object is null, otherwise it is <code>obj.toString()</code> (which 1513: * can be null). 1514: * 1515: * @param obj the Object 1516: * @return the string conversion of obj 1517: */ 1518: public static String valueOf(Object obj) 1519: { 1520: return obj == null ? "null" : obj.toString(); 1521: } 1522: 1523: /** 1524: * Returns a String representation of a character array. Subsequent 1525: * changes to the array do not affect the String. 1526: * 1527: * @param data the character array 1528: * @return a String containing the same character sequence as data 1529: * @throws NullPointerException if data is null 1530: * @see #valueOf(char[], int, int) 1531: * @see #String(char[]) 1532: */ 1533: public static String valueOf(char[] data) 1534: { 1535: return valueOf (data, 0, data.length); 1536: } 1537: 1538: /** 1539: * Returns a String representing the character sequence of the char array, 1540: * starting at the specified offset, and copying chars up to the specified 1541: * count. Subsequent changes to the array do not affect the String. 1542: * 1543: * @param data character array 1544: * @param offset position (base 0) to start copying out of data 1545: * @param count the number of characters from data to copy 1546: * @return String containing the chars from data[offset..offset+count] 1547: * @throws NullPointerException if data is null 1548: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 1549: * || offset + count > data.length) 1550: * (while unspecified, this is a StringIndexOutOfBoundsException) 1551: * @see #String(char[], int, int) 1552: */ 1553: public static String valueOf(char[] data, int offset, int count) 1554: { 1555: return new String(data, offset, count, false); 1556: } 1557: 1558: /** 1559: * Returns a String representing the character sequence of the char array, 1560: * starting at the specified offset, and copying chars up to the specified 1561: * count. Subsequent changes to the array do not affect the String. 1562: * 1563: * @param data character array 1564: * @param offset position (base 0) to start copying out of data 1565: * @param count the number of characters from data to copy 1566: * @return String containing the chars from data[offset..offset+count] 1567: * @throws NullPointerException if data is null 1568: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 1569: * || offset + count > data.length) 1570: * (while unspecified, this is a StringIndexOutOfBoundsException) 1571: * @see #String(char[], int, int) 1572: */ 1573: public static String copyValueOf(char[] data, int offset, int count) 1574: { 1575: return new String(data, offset, count, false); 1576: } 1577: 1578: /** 1579: * Returns a String representation of a character array. Subsequent 1580: * changes to the array do not affect the String. 1581: * 1582: * @param data the character array 1583: * @return a String containing the same character sequence as data 1584: * @throws NullPointerException if data is null 1585: * @see #copyValueOf(char[], int, int) 1586: * @see #String(char[]) 1587: */ 1588: public static String copyValueOf(char[] data) 1589: { 1590: return copyValueOf (data, 0, data.length); 1591: } 1592: 1593: /** 1594: * Returns a String representing a boolean. 1595: * 1596: * @param b the boolean 1597: * @return "true" if b is true, else "false" 1598: */ 1599: public static String valueOf(boolean b) 1600: { 1601: return b ? "true" : "false"; 1602: } 1603: 1604: /** 1605: * Returns a String representing a character. 1606: * 1607: * @param c the character 1608: * @return String containing the single character c 1609: */ 1610: public static String valueOf(char c) 1611: { 1612: // Package constructor avoids an array copy. 1613: return new String(new char[] { c }, 0, 1, true); 1614: } 1615: 1616: /** 1617: * Returns a String representing an integer. 1618: * 1619: * @param i the integer 1620: * @return String containing the integer in base 10 1621: * @see Integer#toString(int) 1622: */ 1623: public static String valueOf(int i) 1624: { 1625: // See Integer to understand why we call the two-arg variant. 1626: return Integer.toString(i, 10); 1627: } 1628: 1629: /** 1630: * Returns a String representing a long. 1631: * 1632: * @param l the long 1633: * @return String containing the long in base 10 1634: * @see Long#toString(long) 1635: */ 1636: public static String valueOf(long l) 1637: { 1638: return Long.toString(l); 1639: } 1640: 1641: /** 1642: * Returns a String representing a float. 1643: * 1644: * @param f the float 1645: * @return String containing the float 1646: * @see Float#toString(float) 1647: */ 1648: public static String valueOf(float f) 1649: { 1650: return Float.toString(f); 1651: } 1652: 1653: /** 1654: * Returns a String representing a double. 1655: * 1656: * @param d the double 1657: * @return String containing the double 1658: * @see Double#toString(double) 1659: */ 1660: public static String valueOf(double d) 1661: { 1662: return Double.toString(d); 1663: } 1664: 1665: /** 1666: * If two Strings are considered equal, by the equals() method, 1667: * then intern() will return the same String instance. ie. 1668: * if (s1.equals(s2)) then (s1.intern() == s2.intern()). 1669: * All string literals and string-valued constant expressions 1670: * are already interned. 1671: * 1672: * @return the interned String 1673: */ 1674: public String intern() 1675: { 1676: return VMString.intern(this); 1677: } 1678: 1679: /** 1680: * Helper function used to detect which characters have a multi-character 1681: * uppercase expansion. Note that this is only used in locations which 1682: * track one-to-many capitalization (java.lang.Character does not do this). 1683: * As of Unicode 3.0.0, the result is limited in the range 0 to 2, as the 1684: * longest uppercase expansion is three characters (a growth of 2 from the 1685: * lowercase character). 1686: * 1687: * @param ch the char to check 1688: * @return the number of characters to add when converting to uppercase 1689: * @see CharData#DIRECTION 1690: * @see CharData#UPPER_SPECIAL 1691: * @see #toUpperCase(Locale) 1692: */ 1693: private static int upperCaseExpansion(char ch) 1694: { 1695: return Character.direction[Character.readChar(ch) >> 7] & 3; 1696: } 1697: 1698: /** 1699: * Helper function used to locate the offset in upperExpand given a 1700: * character with a multi-character expansion. The binary search is 1701: * optimized under the assumption that this method will only be called on 1702: * characters which exist in upperSpecial. 1703: * 1704: * @param ch the char to check 1705: * @return the index where its expansion begins 1706: * @see CharData#UPPER_SPECIAL 1707: * @see CharData#UPPER_EXPAND 1708: * @see #toUpperCase(Locale) 1709: */ 1710: private static int upperCaseIndex(char ch) 1711: { 1712: // Simple binary search for the correct character. 1713: int low = 0; 1714: int hi = upperSpecial.length - 2; 1715: int mid = ((low + hi) >> 2) << 1; 1716: char c = upperSpecial[mid]; 1717: while (ch != c) 1718: { 1719: if (ch < c) 1720: hi = mid - 2; 1721: else 1722: low = mid + 2; 1723: mid = ((low + hi) >> 2) << 1; 1724: c = upperSpecial[mid]; 1725: } 1726: return upperSpecial[mid + 1]; 1727: } 1728: 1729: /** 1730: * Returns the value array of the given string if it is zero based or a 1731: * copy of it that is zero based (stripping offset and making length equal 1732: * to count). Used for accessing the char[]s of gnu.java.lang.CharData. 1733: * Package private for use in Character. 1734: */ 1735: static char[] zeroBasedStringValue(String s) 1736: { 1737: char[] value; 1738: 1739: if (s.offset == 0 && s.count == s.value.length) 1740: value = s.value; 1741: else 1742: { 1743: int count = s.count; 1744: value = new char[count]; 1745: VMSystem.arraycopy(s.value, s.offset, value, 0, count); 1746: } 1747: 1748: return value; 1749: } 1750: }
GNU Classpath (0.18) |