GNU Classpath (0.19) | ||
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(Locale) 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 < 0 (overflow) 237: * || offset + count > data.length) 238: * (while unspecified, this is a StringIndexOutOfBoundsException) 239: */ 240: public String(char[] data, int offset, int count) 241: { 242: this(data, offset, count, false); 243: } 244: 245: /** 246: * Creates a new String using an 8-bit array of integer values, starting at 247: * an offset, and copying up to the count. Each character c, using 248: * corresponding byte b, is created in the new String as if by performing: 249: * 250: * <pre> 251: * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) 252: * </pre> 253: * 254: * @param ascii array of integer values 255: * @param hibyte top byte of each Unicode character 256: * @param offset position (base 0) to start copying out of ascii 257: * @param count the number of characters from ascii to copy 258: * @throws NullPointerException if ascii is null 259: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 260: * || offset + count < 0 (overflow) 261: * || offset + count > ascii.length) 262: * (while unspecified, this is a StringIndexOutOfBoundsException) 263: * @see #String(byte[]) 264: * @see #String(byte[], String) 265: * @see #String(byte[], int, int) 266: * @see #String(byte[], int, int, String) 267: * @deprecated use {@link #String(byte[], int, int, String)} to perform 268: * correct encoding 269: */ 270: public String(byte[] ascii, int hibyte, int offset, int count) 271: { 272: if (offset < 0) 273: throw new StringIndexOutOfBoundsException("offset: " + offset); 274: if (count < 0) 275: throw new StringIndexOutOfBoundsException("count: " + count); 276: if (offset + count < 0 || offset + count > ascii.length) 277: throw new StringIndexOutOfBoundsException("offset + count: " 278: + (offset + count)); 279: value = new char[count]; 280: this.offset = 0; 281: this.count = count; 282: hibyte <<= 8; 283: offset += count; 284: while (--count >= 0) 285: value[count] = (char) (hibyte | (ascii[--offset] & 0xff)); 286: } 287: 288: /** 289: * Creates a new String using an 8-bit array of integer values. Each 290: * character c, using corresponding byte b, is created in the new String 291: * as if by performing: 292: * 293: * <pre> 294: * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) 295: * </pre> 296: * 297: * @param ascii array of integer values 298: * @param hibyte top byte of each Unicode character 299: * @throws NullPointerException if ascii is null 300: * @see #String(byte[]) 301: * @see #String(byte[], String) 302: * @see #String(byte[], int, int) 303: * @see #String(byte[], int, int, String) 304: * @see #String(byte[], int, int, int) 305: * @deprecated use {@link #String(byte[], String)} to perform 306: * correct encoding 307: */ 308: public String(byte[] ascii, int hibyte) 309: { 310: this(ascii, hibyte, 0, ascii.length); 311: } 312: 313: /** 314: * Creates a new String using the portion of the byte array starting at the 315: * offset and ending at offset + count. Uses the specified encoding type 316: * to decode the byte array, so the resulting string may be longer or 317: * shorter than the byte array. For more decoding control, use 318: * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, 319: * see {@link java.nio.charset.Charset}. The behavior is not specified if 320: * the decoder encounters invalid characters; this implementation throws 321: * an Error. 322: * 323: * @param data byte array to copy 324: * @param offset the offset to start at 325: * @param count the number of bytes in the array to use 326: * @param encoding the name of the encoding to use 327: * @throws NullPointerException if data or encoding is null 328: * @throws IndexOutOfBoundsException if offset or count is incorrect 329: * (while unspecified, this is a StringIndexOutOfBoundsException) 330: * @throws UnsupportedEncodingException if encoding is not found 331: * @throws Error if the decoding fails 332: * @since 1.1 333: */ 334: public String(byte[] data, int offset, int count, String encoding) 335: throws UnsupportedEncodingException 336: { 337: if (offset < 0) 338: throw new StringIndexOutOfBoundsException("offset: " + offset); 339: if (count < 0) 340: throw new StringIndexOutOfBoundsException("count: " + count); 341: if (offset + count < 0 || offset + count > data.length) 342: throw new StringIndexOutOfBoundsException("offset + count: " 343: + (offset + count)); 344: try 345: { 346: CharsetDecoder csd = Charset.forName(encoding).newDecoder(); 347: csd.onMalformedInput(CodingErrorAction.REPLACE); 348: csd.onUnmappableCharacter(CodingErrorAction.REPLACE); 349: CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); 350: if(cbuf.hasArray()) 351: { 352: value = cbuf.array(); 353: this.offset = cbuf.position(); 354: this.count = cbuf.remaining(); 355: } else { 356: // Doubt this will happen. But just in case. 357: value = new char[cbuf.remaining()]; 358: cbuf.get(value); 359: this.offset = 0; 360: this.count = value.length; 361: } 362: } catch(CharacterCodingException e){ 363: throw new UnsupportedEncodingException("Encoding: "+encoding+ 364: " not found."); 365: } catch(IllegalCharsetNameException e){ 366: throw new UnsupportedEncodingException("Encoding: "+encoding+ 367: " not found."); 368: } catch(UnsupportedCharsetException e){ 369: throw new UnsupportedEncodingException("Encoding: "+encoding+ 370: " not found."); 371: } 372: } 373: 374: /** 375: * Creates a new String using the byte array. Uses the specified encoding 376: * type to decode the byte array, so the resulting string may be longer or 377: * shorter than the byte array. For more decoding control, use 378: * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, 379: * see {@link java.nio.charset.Charset}. The behavior is not specified if 380: * the decoder encounters invalid characters; this implementation throws 381: * an Error. 382: * 383: * @param data byte array to copy 384: * @param encoding the name of the encoding to use 385: * @throws NullPointerException if data or encoding is null 386: * @throws UnsupportedEncodingException if encoding is not found 387: * @throws Error if the decoding fails 388: * @see #String(byte[], int, int, String) 389: * @since 1.1 390: */ 391: public String(byte[] data, String encoding) 392: throws UnsupportedEncodingException 393: { 394: this(data, 0, data.length, encoding); 395: } 396: 397: /** 398: * Creates a new String using the portion of the byte array starting at the 399: * offset and ending at offset + count. Uses the encoding of the platform's 400: * default charset, so the resulting string may be longer or shorter than 401: * the byte array. For more decoding control, use 402: * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified 403: * if the decoder encounters invalid characters; this implementation throws 404: * an Error. 405: * 406: * @param data byte array to copy 407: * @param offset the offset to start at 408: * @param count the number of bytes in the array to use 409: * @throws NullPointerException if data is null 410: * @throws IndexOutOfBoundsException if offset or count is incorrect 411: * @throws Error if the decoding fails 412: * @see #String(byte[], int, int, String) 413: * @since 1.1 414: */ 415: public String(byte[] data, int offset, int count) 416: { 417: if (offset < 0) 418: throw new StringIndexOutOfBoundsException("offset: " + offset); 419: if (count < 0) 420: throw new StringIndexOutOfBoundsException("count: " + count); 421: if (offset + count < 0 || offset + count > data.length) 422: throw new StringIndexOutOfBoundsException("offset + count: " 423: + (offset + count)); 424: int o, c; 425: char[] v; 426: String encoding; 427: try 428: { 429: encoding = System.getProperty("file.encoding"); 430: CharsetDecoder csd = Charset.forName(encoding).newDecoder(); 431: csd.onMalformedInput(CodingErrorAction.REPLACE); 432: csd.onUnmappableCharacter(CodingErrorAction.REPLACE); 433: CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count)); 434: if(cbuf.hasArray()) 435: { 436: v = cbuf.array(); 437: o = cbuf.position(); 438: c = cbuf.remaining(); 439: } else { 440: // Doubt this will happen. But just in case. 441: v = new char[cbuf.remaining()]; 442: cbuf.get(v); 443: o = 0; 444: c = v.length; 445: } 446: } catch(Exception ex){ 447: // If anything goes wrong (System property not set, 448: // NIO provider not available, etc) 449: // Default to the 'safe' encoding ISO8859_1 450: v = new char[count]; 451: o = 0; 452: c = count; 453: for (int i=0;i<count;i++) 454: v[i] = (char)data[offset+i]; 455: } 456: this.value = v; 457: this.offset = o; 458: this.count = c; 459: } 460: 461: /** 462: * Creates a new String using the byte array. Uses the encoding of the 463: * platform's default charset, so the resulting string may be longer or 464: * shorter than the byte array. For more decoding control, use 465: * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified 466: * if the decoder encounters invalid characters; this implementation throws 467: * an Error. 468: * 469: * @param data byte array to copy 470: * @throws NullPointerException if data is null 471: * @throws Error if the decoding fails 472: * @see #String(byte[], int, int) 473: * @see #String(byte[], int, int, String) 474: * @since 1.1 475: */ 476: public String(byte[] data) 477: { 478: this(data, 0, data.length); 479: } 480: 481: /** 482: * Creates a new String using the character sequence represented by 483: * the StringBuffer. Subsequent changes to buf do not affect the String. 484: * 485: * @param buffer StringBuffer to copy 486: * @throws NullPointerException if buffer is null 487: */ 488: public String(StringBuffer buffer) 489: { 490: synchronized (buffer) 491: { 492: offset = 0; 493: count = buffer.count; 494: // Share unless buffer is 3/4 empty. 495: if ((count << 2) < buffer.value.length) 496: { 497: value = new char[count]; 498: VMSystem.arraycopy(buffer.value, 0, value, 0, count); 499: } 500: else 501: { 502: buffer.shared = true; 503: value = buffer.value; 504: } 505: } 506: } 507: 508: /** 509: * Creates a new String using the character sequence represented by 510: * the StringBuilder. Subsequent changes to buf do not affect the String. 511: * 512: * @param buffer StringBuilder to copy 513: * @throws NullPointerException if buffer is null 514: */ 515: public String(StringBuilder buffer) 516: { 517: this(buffer.value, 0, buffer.count); 518: } 519: 520: /** 521: * Special constructor which can share an array when safe to do so. 522: * 523: * @param data the characters to copy 524: * @param offset the location to start from 525: * @param count the number of characters to use 526: * @param dont_copy true if the array is trusted, and need not be copied 527: * @throws NullPointerException if chars is null 528: * @throws StringIndexOutOfBoundsException if bounds check fails 529: */ 530: String(char[] data, int offset, int count, boolean dont_copy) 531: { 532: if (offset < 0) 533: throw new StringIndexOutOfBoundsException("offset: " + offset); 534: if (count < 0) 535: throw new StringIndexOutOfBoundsException("count: " + count); 536: if (offset + count < 0 || offset + count > data.length) 537: throw new StringIndexOutOfBoundsException("offset + count: " 538: + (offset + count)); 539: if (dont_copy) 540: { 541: value = data; 542: this.offset = offset; 543: } 544: else 545: { 546: value = new char[count]; 547: VMSystem.arraycopy(data, offset, value, 0, count); 548: this.offset = 0; 549: } 550: this.count = count; 551: } 552: 553: /** 554: * Returns the number of characters contained in this String. 555: * 556: * @return the length of this String 557: */ 558: public int length() 559: { 560: return count; 561: } 562: 563: /** 564: * Returns the character located at the specified index within this String. 565: * 566: * @param index position of character to return (base 0) 567: * @return character located at position index 568: * @throws IndexOutOfBoundsException if index < 0 || index >= length() 569: * (while unspecified, this is a StringIndexOutOfBoundsException) 570: */ 571: public char charAt(int index) 572: { 573: if (index < 0 || index >= count) 574: throw new StringIndexOutOfBoundsException(index); 575: return value[offset + index]; 576: } 577: 578: /** 579: * Get the code point at the specified index. This is like #charAt(int), 580: * but if the character is the start of a surrogate pair, and the 581: * following character completes the pair, then the corresponding 582: * supplementary code point is returned. 583: * @param index the index of the codepoint to get, starting at 0 584: * @return the codepoint at the specified index 585: * @throws IndexOutOfBoundsException if index is negative or >= length() 586: * @since 1.5 587: */ 588: public synchronized int codePointAt(int index) 589: { 590: // Use the CharSequence overload as we get better range checking 591: // this way. 592: return Character.codePointAt(this, index); 593: } 594: 595: /** 596: * Get the code point before the specified index. This is like 597: * #codePointAt(int), but checks the characters at <code>index-1</code> and 598: * <code>index-2</code> to see if they form a supplementary code point. 599: * @param index the index just past the codepoint to get, starting at 0 600: * @return the codepoint at the specified index 601: * @throws IndexOutOfBoundsException if index is negative or >= length() 602: * (while unspecified, this is a StringIndexOutOfBoundsException) 603: * @since 1.5 604: */ 605: public synchronized int codePointBefore(int index) 606: { 607: // Use the CharSequence overload as we get better range checking 608: // this way. 609: return Character.codePointBefore(this, index); 610: } 611: 612: /** 613: * Copies characters from this String starting at a specified start index, 614: * ending at a specified stop index, to a character array starting at 615: * a specified destination begin index. 616: * 617: * @param srcBegin index to begin copying characters from this String 618: * @param srcEnd index after the last character to be copied from this String 619: * @param dst character array which this String is copied into 620: * @param dstBegin index to start writing characters into dst 621: * @throws NullPointerException if dst is null 622: * @throws IndexOutOfBoundsException if any indices are out of bounds 623: * (while unspecified, source problems cause a 624: * StringIndexOutOfBoundsException, and dst problems cause an 625: * ArrayIndexOutOfBoundsException) 626: */ 627: public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) 628: { 629: if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) 630: throw new StringIndexOutOfBoundsException(); 631: VMSystem.arraycopy(value, srcBegin + offset, 632: dst, dstBegin, srcEnd - srcBegin); 633: } 634: 635: /** 636: * Copies the low byte of each character from this String starting at a 637: * specified start index, ending at a specified stop index, to a byte array 638: * starting at a specified destination begin index. 639: * 640: * @param srcBegin index to being copying characters from this String 641: * @param srcEnd index after the last character to be copied from this String 642: * @param dst byte array which each low byte of this String is copied into 643: * @param dstBegin index to start writing characters into dst 644: * @throws NullPointerException if dst is null and copy length is non-zero 645: * @throws IndexOutOfBoundsException if any indices are out of bounds 646: * (while unspecified, source problems cause a 647: * StringIndexOutOfBoundsException, and dst problems cause an 648: * ArrayIndexOutOfBoundsException) 649: * @see #getBytes() 650: * @see #getBytes(String) 651: * @deprecated use {@link #getBytes()}, which uses a char to byte encoder 652: */ 653: public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) 654: { 655: if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) 656: throw new StringIndexOutOfBoundsException(); 657: int i = srcEnd - srcBegin; 658: srcBegin += offset; 659: while (--i >= 0) 660: dst[dstBegin++] = (byte) value[srcBegin++]; 661: } 662: 663: /** 664: * Converts the Unicode characters in this String to a byte array. Uses the 665: * specified encoding method, so the result may be longer or shorter than 666: * the String. For more encoding control, use 667: * {@link java.nio.charset.CharsetEncoder}, and for valid character sets, 668: * see {@link java.nio.charset.Charset}. Unsupported characters get 669: * replaced by an encoding specific byte. 670: * 671: * @param enc encoding name 672: * @return the resulting byte array 673: * @throws NullPointerException if enc is null 674: * @throws UnsupportedEncodingException if encoding is not supported 675: * @since 1.1 676: */ 677: public byte[] getBytes(String enc) throws UnsupportedEncodingException 678: { 679: try 680: { 681: CharsetEncoder cse = Charset.forName(enc).newEncoder(); 682: cse.onMalformedInput(CodingErrorAction.REPLACE); 683: cse.onUnmappableCharacter(CodingErrorAction.REPLACE); 684: ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count)); 685: if(bbuf.hasArray()) 686: return bbuf.array(); 687: 688: // Doubt this will happen. But just in case. 689: byte[] bytes = new byte[bbuf.remaining()]; 690: bbuf.get(bytes); 691: return bytes; 692: } 693: catch(IllegalCharsetNameException e) 694: { 695: throw new UnsupportedEncodingException("Encoding: " + enc 696: + " not found."); 697: } 698: catch(UnsupportedCharsetException e) 699: { 700: throw new UnsupportedEncodingException("Encoding: " + enc 701: + " not found."); 702: } 703: catch(CharacterCodingException e) 704: { 705: // This shouldn't ever happen. 706: throw (InternalError) new InternalError().initCause(e); 707: } 708: } 709: 710: /** 711: * Converts the Unicode characters in this String to a byte array. Uses the 712: * encoding of the platform's default charset, so the result may be longer 713: * or shorter than the String. For more encoding control, use 714: * {@link java.nio.charset.CharsetEncoder}. Unsupported characters get 715: * replaced by an encoding specific byte. 716: * 717: * @return the resulting byte array, or null on a problem 718: * @since 1.1 719: */ 720: public byte[] getBytes() 721: { 722: try 723: { 724: return getBytes(System.getProperty("file.encoding")); 725: } catch(Exception e) { 726: // XXX - Throw an error here? 727: // For now, default to the 'safe' encoding. 728: byte[] bytes = new byte[count]; 729: for(int i=0;i<count;i++) 730: bytes[i] = (byte)((value[offset+i] <= 0xFF)? 731: value[offset+i]:'?'); 732: return bytes; 733: } 734: } 735: 736: /** 737: * Predicate which compares anObject to this. This is true only for Strings 738: * with the same character sequence. 739: * 740: * @param anObject the object to compare 741: * @return true if anObject is semantically equal to this 742: * @see #compareTo(String) 743: * @see #equalsIgnoreCase(String) 744: */ 745: public boolean equals(Object anObject) 746: { 747: if (! (anObject instanceof String)) 748: return false; 749: String str2 = (String) anObject; 750: if (count != str2.count) 751: return false; 752: if (value == str2.value && offset == str2.offset) 753: return true; 754: int i = count; 755: int x = offset; 756: int y = str2.offset; 757: while (--i >= 0) 758: if (value[x++] != str2.value[y++]) 759: return false; 760: return true; 761: } 762: 763: /** 764: * Compares the given StringBuffer to this String. This is true if the 765: * StringBuffer has the same content as this String at this moment. 766: * 767: * @param buffer the StringBuffer to compare to 768: * @return true if StringBuffer has the same character sequence 769: * @throws NullPointerException if the given StringBuffer is null 770: * @since 1.4 771: */ 772: public boolean contentEquals(StringBuffer buffer) 773: { 774: synchronized (buffer) 775: { 776: if (count != buffer.count) 777: return false; 778: if (value == buffer.value) 779: return true; // Possible if shared. 780: int i = count; 781: int x = offset + count; 782: while (--i >= 0) 783: if (value[--x] != buffer.value[i]) 784: return false; 785: return true; 786: } 787: } 788: 789: /** 790: * Compares the given CharSequence to this String. This is true if 791: * the CharSequence has the same content as this String at this 792: * moment. 793: * 794: * @param seq the CharSequence to compare to 795: * @return true if CharSequence has the same character sequence 796: * @throws NullPointerException if the given CharSequence is null 797: * @since 1.5 798: */ 799: public boolean contentEquals(CharSequence seq) 800: { 801: if (seq.length() != count) 802: return false; 803: for (int i = 0; i < count; ++i) 804: if (value[offset + i] != seq.charAt(i)) 805: return false; 806: return true; 807: } 808: 809: /** 810: * Compares a String to this String, ignoring case. This does not handle 811: * multi-character capitalization exceptions; instead the comparison is 812: * made on a character-by-character basis, and is true if:<br><ul> 813: * <li><code>c1 == c2</code></li> 814: * <li><code>Character.toUpperCase(c1) 815: * == Character.toUpperCase(c2)</code></li> 816: * <li><code>Character.toLowerCase(c1) 817: * == Character.toLowerCase(c2)</code></li> 818: * </ul> 819: * 820: * @param anotherString String to compare to this String 821: * @return true if anotherString is equal, ignoring case 822: * @see #equals(Object) 823: * @see Character#toUpperCase(char) 824: * @see Character#toLowerCase(char) 825: */ 826: public boolean equalsIgnoreCase(String anotherString) 827: { 828: if (anotherString == null || count != anotherString.count) 829: return false; 830: int i = count; 831: int x = offset; 832: int y = anotherString.offset; 833: while (--i >= 0) 834: { 835: char c1 = value[x++]; 836: char c2 = anotherString.value[y++]; 837: // Note that checking c1 != c2 is redundant, but avoids method calls. 838: if (c1 != c2 839: && Character.toUpperCase(c1) != Character.toUpperCase(c2) 840: && Character.toLowerCase(c1) != Character.toLowerCase(c2)) 841: return false; 842: } 843: return true; 844: } 845: 846: /** 847: * Compares this String and another String (case sensitive, 848: * lexicographically). The result is less than 0 if this string sorts 849: * before the other, 0 if they are equal, and greater than 0 otherwise. 850: * After any common starting sequence is skipped, the result is 851: * <code>this.charAt(k) - anotherString.charAt(k)</code> if both strings 852: * have characters remaining, or 853: * <code>this.length() - anotherString.length()</code> if one string is 854: * a subsequence of the other. 855: * 856: * @param anotherString the String to compare against 857: * @return the comparison 858: * @throws NullPointerException if anotherString is null 859: */ 860: public int compareTo(String anotherString) 861: { 862: int i = Math.min(count, anotherString.count); 863: int x = offset; 864: int y = anotherString.offset; 865: while (--i >= 0) 866: { 867: int result = value[x++] - anotherString.value[y++]; 868: if (result != 0) 869: return result; 870: } 871: return count - anotherString.count; 872: } 873: 874: /** 875: * Behaves like <code>compareTo(java.lang.String)</code> unless the Object 876: * is not a <code>String</code>. Then it throws a 877: * <code>ClassCastException</code>. 878: * 879: * @param o the object to compare against 880: * @return the comparison 881: * @throws NullPointerException if o is null 882: * @throws ClassCastException if o is not a <code>String</code> 883: * @since 1.2 884: */ 885: public int compareTo(Object o) 886: { 887: return compareTo((String) o); 888: } 889: 890: /** 891: * Compares this String and another String (case insensitive). This 892: * comparison is <em>similar</em> to equalsIgnoreCase, in that it ignores 893: * locale and multi-characater capitalization, and compares characters 894: * after performing 895: * <code>Character.toLowerCase(Character.toUpperCase(c))</code> on each 896: * character of the string. This is unsatisfactory for locale-based 897: * comparison, in which case you should use {@link java.text.Collator}. 898: * 899: * @param str the string to compare against 900: * @return the comparison 901: * @see Collator#compare(String, String) 902: * @since 1.2 903: */ 904: public int compareToIgnoreCase(String str) 905: { 906: int i = Math.min(count, str.count); 907: int x = offset; 908: int y = str.offset; 909: while (--i >= 0) 910: { 911: int result = Character.toLowerCase(Character.toUpperCase(value[x++])) 912: - Character.toLowerCase(Character.toUpperCase(str.value[y++])); 913: if (result != 0) 914: return result; 915: } 916: return count - str.count; 917: } 918: 919: /** 920: * Predicate which determines if this String matches another String 921: * starting at a specified offset for each String and continuing 922: * for a specified length. Indices out of bounds are harmless, and give 923: * a false result. 924: * 925: * @param toffset index to start comparison at for this String 926: * @param other String to compare region to this String 927: * @param ooffset index to start comparison at for other 928: * @param len number of characters to compare 929: * @return true if regions match (case sensitive) 930: * @throws NullPointerException if other is null 931: */ 932: public boolean regionMatches(int toffset, String other, int ooffset, int len) 933: { 934: return regionMatches(false, toffset, other, ooffset, len); 935: } 936: 937: /** 938: * Predicate which determines if this String matches another String 939: * starting at a specified offset for each String and continuing 940: * for a specified length, optionally ignoring case. Indices out of bounds 941: * are harmless, and give a false result. Case comparisons are based on 942: * <code>Character.toLowerCase()</code> and 943: * <code>Character.toUpperCase()</code>, not on multi-character 944: * capitalization expansions. 945: * 946: * @param ignoreCase true if case should be ignored in comparision 947: * @param toffset index to start comparison at for this String 948: * @param other String to compare region to this String 949: * @param ooffset index to start comparison at for other 950: * @param len number of characters to compare 951: * @return true if regions match, false otherwise 952: * @throws NullPointerException if other is null 953: */ 954: public boolean regionMatches(boolean ignoreCase, int toffset, 955: String other, int ooffset, int len) 956: { 957: if (toffset < 0 || ooffset < 0 || toffset + len > count 958: || ooffset + len > other.count) 959: return false; 960: toffset += offset; 961: ooffset += other.offset; 962: while (--len >= 0) 963: { 964: char c1 = value[toffset++]; 965: char c2 = other.value[ooffset++]; 966: // Note that checking c1 != c2 is redundant when ignoreCase is true, 967: // but it avoids method calls. 968: if (c1 != c2 969: && (! ignoreCase 970: || (Character.toLowerCase(c1) != Character.toLowerCase(c2) 971: && (Character.toUpperCase(c1) 972: != Character.toUpperCase(c2))))) 973: return false; 974: } 975: return true; 976: } 977: 978: /** 979: * Predicate which determines if this String contains the given prefix, 980: * beginning comparison at toffset. The result is false if toffset is 981: * negative or greater than this.length(), otherwise it is the same as 982: * <code>this.substring(toffset).startsWith(prefix)</code>. 983: * 984: * @param prefix String to compare 985: * @param toffset offset for this String where comparison starts 986: * @return true if this String starts with prefix 987: * @throws NullPointerException if prefix is null 988: * @see #regionMatches(boolean, int, String, int, int) 989: */ 990: public boolean startsWith(String prefix, int toffset) 991: { 992: return regionMatches(false, toffset, prefix, 0, prefix.count); 993: } 994: 995: /** 996: * Predicate which determines if this String starts with a given prefix. 997: * If the prefix is an empty String, true is returned. 998: * 999: * @param prefix String to compare 1000: * @return true if this String starts with the prefix 1001: * @throws NullPointerException if prefix is null 1002: * @see #startsWith(String, int) 1003: */ 1004: public boolean startsWith(String prefix) 1005: { 1006: return regionMatches(false, 0, prefix, 0, prefix.count); 1007: } 1008: 1009: /** 1010: * Predicate which determines if this String ends with a given suffix. 1011: * If the suffix is an empty String, true is returned. 1012: * 1013: * @param suffix String to compare 1014: * @return true if this String ends with the suffix 1015: * @throws NullPointerException if suffix is null 1016: * @see #regionMatches(boolean, int, String, int, int) 1017: */ 1018: public boolean endsWith(String suffix) 1019: { 1020: return regionMatches(false, count - suffix.count, suffix, 0, suffix.count); 1021: } 1022: 1023: /** 1024: * Computes the hashcode for this String. This is done with int arithmetic, 1025: * where ** represents exponentiation, by this formula:<br> 1026: * <code>s[0]*31**(n-1) + s[1]*31**(n-2) + ... + s[n-1]</code>. 1027: * 1028: * @return hashcode value of this String 1029: */ 1030: public int hashCode() 1031: { 1032: if (cachedHashCode != 0) 1033: return cachedHashCode; 1034: 1035: // Compute the hash code using a local variable to be reentrant. 1036: int hashCode = 0; 1037: int limit = count + offset; 1038: for (int i = offset; i < limit; i++) 1039: hashCode = hashCode * 31 + value[i]; 1040: return cachedHashCode = hashCode; 1041: } 1042: 1043: /** 1044: * Finds the first instance of a character in this String. 1045: * 1046: * @param ch character to find 1047: * @return location (base 0) of the character, or -1 if not found 1048: */ 1049: public int indexOf(int ch) 1050: { 1051: return indexOf(ch, 0); 1052: } 1053: 1054: /** 1055: * Finds the first instance of a character in this String, starting at 1056: * a given index. If starting index is less than 0, the search 1057: * starts at the beginning of this String. If the starting index 1058: * is greater than the length of this String, -1 is returned. 1059: * 1060: * @param ch character to find 1061: * @param fromIndex index to start the search 1062: * @return location (base 0) of the character, or -1 if not found 1063: */ 1064: public int indexOf(int ch, int fromIndex) 1065: { 1066: if ((char) ch != ch) 1067: return -1; 1068: if (fromIndex < 0) 1069: fromIndex = 0; 1070: int i = fromIndex + offset; 1071: for ( ; fromIndex < count; fromIndex++) 1072: if (value[i++] == ch) 1073: return fromIndex; 1074: return -1; 1075: } 1076: 1077: /** 1078: * Finds the last instance of a character in this String. 1079: * 1080: * @param ch character to find 1081: * @return location (base 0) of the character, or -1 if not found 1082: */ 1083: public int lastIndexOf(int ch) 1084: { 1085: return lastIndexOf(ch, count - 1); 1086: } 1087: 1088: /** 1089: * Finds the last instance of a character in this String, starting at 1090: * a given index. If starting index is greater than the maximum valid 1091: * index, then the search begins at the end of this String. If the 1092: * starting index is less than zero, -1 is returned. 1093: * 1094: * @param ch character to find 1095: * @param fromIndex index to start the search 1096: * @return location (base 0) of the character, or -1 if not found 1097: */ 1098: public int lastIndexOf(int ch, int fromIndex) 1099: { 1100: if ((char) ch != ch) 1101: return -1; 1102: if (fromIndex >= count) 1103: fromIndex = count - 1; 1104: int i = fromIndex + offset; 1105: for ( ; fromIndex >= 0; fromIndex--) 1106: if (value[i--] == ch) 1107: return fromIndex; 1108: return -1; 1109: } 1110: 1111: /** 1112: * Finds the first instance of a String in this String. 1113: * 1114: * @param str String to find 1115: * @return location (base 0) of the String, or -1 if not found 1116: * @throws NullPointerException if str is null 1117: */ 1118: public int indexOf(String str) 1119: { 1120: return indexOf(str, 0); 1121: } 1122: 1123: /** 1124: * Finds the first instance of a String in this String, starting at 1125: * a given index. If starting index is less than 0, the search 1126: * starts at the beginning of this String. If the starting index 1127: * is greater than the length of this String, -1 is returned. 1128: * 1129: * @param str String to find 1130: * @param fromIndex index to start the search 1131: * @return location (base 0) of the String, or -1 if not found 1132: * @throws NullPointerException if str is null 1133: */ 1134: public int indexOf(String str, int fromIndex) 1135: { 1136: if (fromIndex < 0) 1137: fromIndex = 0; 1138: int limit = count - str.count; 1139: for ( ; fromIndex <= limit; fromIndex++) 1140: if (regionMatches(fromIndex, str, 0, str.count)) 1141: return fromIndex; 1142: return -1; 1143: } 1144: 1145: /** 1146: * Finds the last instance of a String in this String. 1147: * 1148: * @param str String to find 1149: * @return location (base 0) of the String, or -1 if not found 1150: * @throws NullPointerException if str is null 1151: */ 1152: public int lastIndexOf(String str) 1153: { 1154: return lastIndexOf(str, count - str.count); 1155: } 1156: 1157: /** 1158: * Finds the last instance of a String in this String, starting at 1159: * a given index. If starting index is greater than the maximum valid 1160: * index, then the search begins at the end of this String. If the 1161: * starting index is less than zero, -1 is returned. 1162: * 1163: * @param str String to find 1164: * @param fromIndex index to start the search 1165: * @return location (base 0) of the String, or -1 if not found 1166: * @throws NullPointerException if str is null 1167: */ 1168: public int lastIndexOf(String str, int fromIndex) 1169: { 1170: fromIndex = Math.min(fromIndex, count - str.count); 1171: for ( ; fromIndex >= 0; fromIndex--) 1172: if (regionMatches(fromIndex, str, 0, str.count)) 1173: return fromIndex; 1174: return -1; 1175: } 1176: 1177: /** 1178: * Creates a substring of this String, starting at a specified index 1179: * and ending at the end of this String. 1180: * 1181: * @param begin index to start substring (base 0) 1182: * @return new String which is a substring of this String 1183: * @throws IndexOutOfBoundsException if begin < 0 || begin > length() 1184: * (while unspecified, this is a StringIndexOutOfBoundsException) 1185: */ 1186: public String substring(int begin) 1187: { 1188: return substring(begin, count); 1189: } 1190: 1191: /** 1192: * Creates a substring of this String, starting at a specified index 1193: * and ending at one character before a specified index. 1194: * 1195: * @param beginIndex index to start substring (inclusive, base 0) 1196: * @param endIndex index to end at (exclusive) 1197: * @return new String which is a substring of this String 1198: * @throws IndexOutOfBoundsException if begin < 0 || end > length() 1199: * || begin > end (while unspecified, this is a 1200: * StringIndexOutOfBoundsException) 1201: */ 1202: public String substring(int beginIndex, int endIndex) 1203: { 1204: if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) 1205: throw new StringIndexOutOfBoundsException(); 1206: if (beginIndex == 0 && endIndex == count) 1207: return this; 1208: int len = endIndex - beginIndex; 1209: // Package constructor avoids an array copy. 1210: return new String(value, beginIndex + offset, len, 1211: (len << 2) >= value.length); 1212: } 1213: 1214: /** 1215: * Creates a substring of this String, starting at a specified index 1216: * and ending at one character before a specified index. This behaves like 1217: * <code>substring(begin, end)</code>. 1218: * 1219: * @param begin index to start substring (inclusive, base 0) 1220: * @param end index to end at (exclusive) 1221: * @return new String which is a substring of this String 1222: * @throws IndexOutOfBoundsException if begin < 0 || end > length() 1223: * || begin > end 1224: * @since 1.4 1225: */ 1226: public CharSequence subSequence(int begin, int end) 1227: { 1228: return substring(begin, end); 1229: } 1230: 1231: /** 1232: * Concatenates a String to this String. This results in a new string unless 1233: * one of the two originals is "". 1234: * 1235: * @param str String to append to this String 1236: * @return newly concatenated String 1237: * @throws NullPointerException if str is null 1238: */ 1239: public String concat(String str) 1240: { 1241: if (str.count == 0) 1242: return this; 1243: if (count == 0) 1244: return str; 1245: char[] newStr = new char[count + str.count]; 1246: VMSystem.arraycopy(value, offset, newStr, 0, count); 1247: VMSystem.arraycopy(str.value, str.offset, newStr, count, str.count); 1248: // Package constructor avoids an array copy. 1249: return new String(newStr, 0, newStr.length, true); 1250: } 1251: 1252: /** 1253: * Replaces every instance of a character in this String with a new 1254: * character. If no replacements occur, this is returned. 1255: * 1256: * @param oldChar the old character to replace 1257: * @param newChar the new character 1258: * @return new String with all instances of oldChar replaced with newChar 1259: */ 1260: public String replace(char oldChar, char newChar) 1261: { 1262: if (oldChar == newChar) 1263: return this; 1264: int i = count; 1265: int x = offset - 1; 1266: while (--i >= 0) 1267: if (value[++x] == oldChar) 1268: break; 1269: if (i < 0) 1270: return this; 1271: char[] newStr = (char[]) value.clone(); 1272: newStr[x] = newChar; 1273: while (--i >= 0) 1274: if (value[++x] == oldChar) 1275: newStr[x] = newChar; 1276: // Package constructor avoids an array copy. 1277: return new String(newStr, offset, count, true); 1278: } 1279: 1280: /** 1281: * Test if this String matches a regular expression. This is shorthand for 1282: * <code>{@link Pattern}.matches(regex, this)</code>. 1283: * 1284: * @param regex the pattern to match 1285: * @return true if the pattern matches 1286: * @throws NullPointerException if regex is null 1287: * @throws PatternSyntaxException if regex is invalid 1288: * @see Pattern#matches(String, CharSequence) 1289: * @since 1.4 1290: */ 1291: public boolean matches(String regex) 1292: { 1293: return Pattern.matches(regex, this); 1294: } 1295: 1296: /** 1297: * Replaces the first substring match of the regular expression with a 1298: * given replacement. This is shorthand for <code>{@link Pattern} 1299: * .compile(regex).matcher(this).replaceFirst(replacement)</code>. 1300: * 1301: * @param regex the pattern to match 1302: * @param replacement the replacement string 1303: * @return the modified string 1304: * @throws NullPointerException if regex or replacement is null 1305: * @throws PatternSyntaxException if regex is invalid 1306: * @see #replaceAll(String, String) 1307: * @see Pattern#compile(String) 1308: * @see Pattern#matcher(CharSequence) 1309: * @see Matcher#replaceFirst(String) 1310: * @since 1.4 1311: */ 1312: public String replaceFirst(String regex, String replacement) 1313: { 1314: return Pattern.compile(regex).matcher(this).replaceFirst(replacement); 1315: } 1316: 1317: /** 1318: * Replaces all matching substrings of the regular expression with a 1319: * given replacement. This is shorthand for <code>{@link Pattern} 1320: * .compile(regex).matcher(this).replaceAll(replacement)</code>. 1321: * 1322: * @param regex the pattern to match 1323: * @param replacement the replacement string 1324: * @return the modified string 1325: * @throws NullPointerException if regex or replacement is null 1326: * @throws PatternSyntaxException if regex is invalid 1327: * @see #replaceFirst(String, String) 1328: * @see Pattern#compile(String) 1329: * @see Pattern#matcher(CharSequence) 1330: * @see Matcher#replaceAll(String) 1331: * @since 1.4 1332: */ 1333: public String replaceAll(String regex, String replacement) 1334: { 1335: return Pattern.compile(regex).matcher(this).replaceAll(replacement); 1336: } 1337: 1338: /** 1339: * Split this string around the matches of a regular expression. Each 1340: * element of the returned array is the largest block of characters not 1341: * terminated by the regular expression, in the order the matches are found. 1342: * 1343: * <p>The limit affects the length of the array. If it is positive, the 1344: * array will contain at most n elements (n - 1 pattern matches). If 1345: * negative, the array length is unlimited, but there can be trailing empty 1346: * entries. if 0, the array length is unlimited, and trailing empty entries 1347: * are discarded. 1348: * 1349: * <p>For example, splitting "boo:and:foo" yields:<br> 1350: * <table border=0> 1351: * <th><td>Regex</td> <td>Limit</td> <td>Result</td></th> 1352: * <tr><td>":"</td> <td>2</td> <td>{ "boo", "and:foo" }</td></tr> 1353: * <tr><td>":"</td> <td>t</td> <td>{ "boo", "and", "foo" }</td></tr> 1354: * <tr><td>":"</td> <td>-2</td> <td>{ "boo", "and", "foo" }</td></tr> 1355: * <tr><td>"o"</td> <td>5</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> 1356: * <tr><td>"o"</td> <td>-2</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> 1357: * <tr><td>"o"</td> <td>0</td> <td>{ "b", "", ":and:f" }</td></tr> 1358: * </table> 1359: * 1360: * <p>This is shorthand for 1361: * <code>{@link Pattern}.compile(regex).split(this, limit)</code>. 1362: * 1363: * @param regex the pattern to match 1364: * @param limit the limit threshold 1365: * @return the array of split strings 1366: * @throws NullPointerException if regex or replacement is null 1367: * @throws PatternSyntaxException if regex is invalid 1368: * @see Pattern#compile(String) 1369: * @see Pattern#split(CharSequence, int) 1370: * @since 1.4 1371: */ 1372: public String[] split(String regex, int limit) 1373: { 1374: return Pattern.compile(regex).split(this, limit); 1375: } 1376: 1377: /** 1378: * Split this string around the matches of a regular expression. Each 1379: * element of the returned array is the largest block of characters not 1380: * terminated by the regular expression, in the order the matches are found. 1381: * The array length is unlimited, and trailing empty entries are discarded, 1382: * as though calling <code>split(regex, 0)</code>. 1383: * 1384: * @param regex the pattern to match 1385: * @return the array of split strings 1386: * @throws NullPointerException if regex or replacement is null 1387: * @throws PatternSyntaxException if regex is invalid 1388: * @see #split(String, int) 1389: * @see Pattern#compile(String) 1390: * @see Pattern#split(CharSequence, int) 1391: * @since 1.4 1392: */ 1393: public String[] split(String regex) 1394: { 1395: return Pattern.compile(regex).split(this, 0); 1396: } 1397: 1398: /** 1399: * Lowercases this String according to a particular locale. This uses 1400: * Unicode's special case mappings, as applied to the given Locale, so the 1401: * resulting string may be a different length. 1402: * 1403: * @param loc locale to use 1404: * @return new lowercased String, or this if no characters were lowercased 1405: * @throws NullPointerException if loc is null 1406: * @see #toUpperCase(Locale) 1407: * @since 1.1 1408: */ 1409: public String toLowerCase(Locale loc) 1410: { 1411: // First, see if the current string is already lower case. 1412: boolean turkish = "tr".equals(loc.getLanguage()); 1413: int i = count; 1414: int x = offset - 1; 1415: while (--i >= 0) 1416: { 1417: char ch = value[++x]; 1418: if ((turkish && ch == '\u0049') 1419: || ch != Character.toLowerCase(ch)) 1420: break; 1421: } 1422: if (i < 0) 1423: return this; 1424: 1425: // Now we perform the conversion. Fortunately, there are no multi-character 1426: // lowercase expansions in Unicode 3.0.0. 1427: char[] newStr = (char[]) value.clone(); 1428: do 1429: { 1430: char ch = value[x]; 1431: // Hardcoded special case. 1432: newStr[x++] = (turkish && ch == '\u0049') ? '\u0131' 1433: : Character.toLowerCase(ch); 1434: } 1435: while (--i >= 0); 1436: // Package constructor avoids an array copy. 1437: return new String(newStr, offset, count, true); 1438: } 1439: 1440: /** 1441: * Lowercases this String. This uses Unicode's special case mappings, as 1442: * applied to the platform's default Locale, so the resulting string may 1443: * be a different length. 1444: * 1445: * @return new lowercased String, or this if no characters were lowercased 1446: * @see #toLowerCase(Locale) 1447: * @see #toUpperCase() 1448: */ 1449: public String toLowerCase() 1450: { 1451: return toLowerCase(Locale.getDefault()); 1452: } 1453: 1454: /** 1455: * Uppercases this String according to a particular locale. This uses 1456: * Unicode's special case mappings, as applied to the given Locale, so the 1457: * resulting string may be a different length. 1458: * 1459: * @param loc locale to use 1460: * @return new uppercased String, or this if no characters were uppercased 1461: * @throws NullPointerException if loc is null 1462: * @see #toLowerCase(Locale) 1463: * @since 1.1 1464: */ 1465: public String toUpperCase(Locale loc) 1466: { 1467: // First, see how many characters we have to grow by, as well as if the 1468: // current string is already upper case. 1469: boolean turkish = "tr".equals(loc.getLanguage()); 1470: int expand = 0; 1471: boolean unchanged = true; 1472: int i = count; 1473: int x = i + offset; 1474: while (--i >= 0) 1475: { 1476: char ch = value[--x]; 1477: expand += upperCaseExpansion(ch); 1478: unchanged = (unchanged && expand == 0 1479: && ! (turkish && ch == '\u0069') 1480: && ch == Character.toUpperCase(ch)); 1481: } 1482: if (unchanged) 1483: return this; 1484: 1485: // Now we perform the conversion. 1486: i = count; 1487: if (expand == 0) 1488: { 1489: char[] newStr = (char[]) value.clone(); 1490: while (--i >= 0) 1491: { 1492: char ch = value[x]; 1493: // Hardcoded special case. 1494: newStr[x++] = (turkish && ch == '\u0069') ? '\u0130' 1495: : Character.toUpperCase(ch); 1496: } 1497: // Package constructor avoids an array copy. 1498: return new String(newStr, offset, count, true); 1499: } 1500: 1501: // Expansion is necessary. 1502: char[] newStr = new char[count + expand]; 1503: int j = 0; 1504: while (--i >= 0) 1505: { 1506: char ch = value[x++]; 1507: // Hardcoded special case. 1508: if (turkish && ch == '\u0069') 1509: { 1510: newStr[j++] = '\u0130'; 1511: continue; 1512: } 1513: expand = upperCaseExpansion(ch); 1514: if (expand > 0) 1515: { 1516: int index = upperCaseIndex(ch); 1517: while (expand-- >= 0) 1518: newStr[j++] = upperExpand[index++]; 1519: } 1520: else 1521: newStr[j++] = Character.toUpperCase(ch); 1522: } 1523: // Package constructor avoids an array copy. 1524: return new String(newStr, 0, newStr.length, true); 1525: } 1526: 1527: /** 1528: * Uppercases this String. This uses Unicode's special case mappings, as 1529: * applied to the platform's default Locale, so the resulting string may 1530: * be a different length. 1531: * 1532: * @return new uppercased String, or this if no characters were uppercased 1533: * @see #toUpperCase(Locale) 1534: * @see #toLowerCase() 1535: */ 1536: public String toUpperCase() 1537: { 1538: return toUpperCase(Locale.getDefault()); 1539: } 1540: 1541: /** 1542: * Trims all characters less than or equal to <code>'\u0020'</code> 1543: * (<code>' '</code>) from the beginning and end of this String. This 1544: * includes many, but not all, ASCII control characters, and all 1545: * {@link Character#isWhitespace(char)}. 1546: * 1547: * @return new trimmed String, or this if nothing trimmed 1548: */ 1549: public String trim() 1550: { 1551: int limit = count + offset; 1552: if (count == 0 || (value[offset] > '\u0020' 1553: && value[limit - 1] > '\u0020')) 1554: return this; 1555: int begin = offset; 1556: do 1557: if (begin == limit) 1558: return ""; 1559: while (value[begin++] <= '\u0020'); 1560: int end = limit; 1561: while (value[--end] <= '\u0020'); 1562: return substring(begin - offset - 1, end - offset + 1); 1563: } 1564: 1565: /** 1566: * Returns this, as it is already a String! 1567: * 1568: * @return this 1569: */ 1570: public String toString() 1571: { 1572: return this; 1573: } 1574: 1575: /** 1576: * Copies the contents of this String into a character array. Subsequent 1577: * changes to the array do not affect the String. 1578: * 1579: * @return character array copying the String 1580: */ 1581: public char[] toCharArray() 1582: { 1583: if (count == value.length) 1584: return (char[]) value.clone(); 1585: 1586: char[] copy = new char[count]; 1587: VMSystem.arraycopy(value, offset, copy, 0, count); 1588: return copy; 1589: } 1590: 1591: /** 1592: * Returns a String representation of an Object. This is "null" if the 1593: * object is null, otherwise it is <code>obj.toString()</code> (which 1594: * can be null). 1595: * 1596: * @param obj the Object 1597: * @return the string conversion of obj 1598: */ 1599: public static String valueOf(Object obj) 1600: { 1601: return obj == null ? "null" : obj.toString(); 1602: } 1603: 1604: /** 1605: * Returns a String representation of a character array. Subsequent 1606: * changes to the array do not affect the String. 1607: * 1608: * @param data the character array 1609: * @return a String containing the same character sequence as data 1610: * @throws NullPointerException if data is null 1611: * @see #valueOf(char[], int, int) 1612: * @see #String(char[]) 1613: */ 1614: public static String valueOf(char[] data) 1615: { 1616: return valueOf (data, 0, data.length); 1617: } 1618: 1619: /** 1620: * Returns a String representing the character sequence of the char array, 1621: * starting at the specified offset, and copying chars up to the specified 1622: * count. Subsequent changes to the array do not affect the String. 1623: * 1624: * @param data character array 1625: * @param offset position (base 0) to start copying out of data 1626: * @param count the number of characters from data to copy 1627: * @return String containing the chars from data[offset..offset+count] 1628: * @throws NullPointerException if data is null 1629: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 1630: * || offset + count < 0 (overflow) 1631: * || offset + count > data.length) 1632: * (while unspecified, this is a StringIndexOutOfBoundsException) 1633: * @see #String(char[], int, int) 1634: */ 1635: public static String valueOf(char[] data, int offset, int count) 1636: { 1637: return new String(data, offset, count, false); 1638: } 1639: 1640: /** 1641: * Returns a String representing the character sequence of the char array, 1642: * starting at the specified offset, and copying chars up to the specified 1643: * count. Subsequent changes to the array do not affect the String. 1644: * 1645: * @param data character array 1646: * @param offset position (base 0) to start copying out of data 1647: * @param count the number of characters from data to copy 1648: * @return String containing the chars from data[offset..offset+count] 1649: * @throws NullPointerException if data is null 1650: * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 1651: * || offset + count < 0 (overflow) 1652: * || offset + count > data.length) 1653: * (while unspecified, this is a StringIndexOutOfBoundsException) 1654: * @see #String(char[], int, int) 1655: */ 1656: public static String copyValueOf(char[] data, int offset, int count) 1657: { 1658: return new String(data, offset, count, false); 1659: } 1660: 1661: /** 1662: * Returns a String representation of a character array. Subsequent 1663: * changes to the array do not affect the String. 1664: * 1665: * @param data the character array 1666: * @return a String containing the same character sequence as data 1667: * @throws NullPointerException if data is null 1668: * @see #copyValueOf(char[], int, int) 1669: * @see #String(char[]) 1670: */ 1671: public static String copyValueOf(char[] data) 1672: { 1673: return copyValueOf (data, 0, data.length); 1674: } 1675: 1676: /** 1677: * Returns a String representing a boolean. 1678: * 1679: * @param b the boolean 1680: * @return "true" if b is true, else "false" 1681: */ 1682: public static String valueOf(boolean b) 1683: { 1684: return b ? "true" : "false"; 1685: } 1686: 1687: /** 1688: * Returns a String representing a character. 1689: * 1690: * @param c the character 1691: * @return String containing the single character c 1692: */ 1693: public static String valueOf(char c) 1694: { 1695: // Package constructor avoids an array copy. 1696: return new String(new char[] { c }, 0, 1, true); 1697: } 1698: 1699: /** 1700: * Returns a String representing an integer. 1701: * 1702: * @param i the integer 1703: * @return String containing the integer in base 10 1704: * @see Integer#toString(int) 1705: */ 1706: public static String valueOf(int i) 1707: { 1708: // See Integer to understand why we call the two-arg variant. 1709: return Integer.toString(i, 10); 1710: } 1711: 1712: /** 1713: * Returns a String representing a long. 1714: * 1715: * @param l the long 1716: * @return String containing the long in base 10 1717: * @see Long#toString(long) 1718: */ 1719: public static String valueOf(long l) 1720: { 1721: return Long.toString(l); 1722: } 1723: 1724: /** 1725: * Returns a String representing a float. 1726: * 1727: * @param f the float 1728: * @return String containing the float 1729: * @see Float#toString(float) 1730: */ 1731: public static String valueOf(float f) 1732: { 1733: return Float.toString(f); 1734: } 1735: 1736: /** 1737: * Returns a String representing a double. 1738: * 1739: * @param d the double 1740: * @return String containing the double 1741: * @see Double#toString(double) 1742: */ 1743: public static String valueOf(double d) 1744: { 1745: return Double.toString(d); 1746: } 1747: 1748: /** 1749: * If two Strings are considered equal, by the equals() method, 1750: * then intern() will return the same String instance. ie. 1751: * if (s1.equals(s2)) then (s1.intern() == s2.intern()). 1752: * All string literals and string-valued constant expressions 1753: * are already interned. 1754: * 1755: * @return the interned String 1756: */ 1757: public String intern() 1758: { 1759: return VMString.intern(this); 1760: } 1761: 1762: /** 1763: * Return the number of code points between two indices in the 1764: * <code>StringBuffer</code>. An unpaired surrogate counts as a 1765: * code point for this purpose. Characters outside the indicated 1766: * range are not examined, even if the range ends in the middle of a 1767: * surrogate pair. 1768: * 1769: * @param start the starting index 1770: * @param end one past the ending index 1771: * @return the number of code points 1772: * @since 1.5 1773: */ 1774: public synchronized int codePointCount(int start, int end) 1775: { 1776: if (start < 0 || end >= count || start > end) 1777: throw new StringIndexOutOfBoundsException(); 1778: 1779: start += offset; 1780: end += offset; 1781: int count = 0; 1782: while (start < end) 1783: { 1784: char base = value[start]; 1785: if (base < Character.MIN_HIGH_SURROGATE 1786: || base > Character.MAX_HIGH_SURROGATE 1787: || start == end 1788: || start == count 1789: || value[start + 1] < Character.MIN_LOW_SURROGATE 1790: || value[start + 1] > Character.MAX_LOW_SURROGATE) 1791: { 1792: // Nothing. 1793: } 1794: else 1795: { 1796: // Surrogate pair. 1797: ++start; 1798: } 1799: ++start; 1800: ++count; 1801: } 1802: return count; 1803: } 1804: 1805: /** 1806: * Helper function used to detect which characters have a multi-character 1807: * uppercase expansion. Note that this is only used in locations which 1808: * track one-to-many capitalization (java.lang.Character does not do this). 1809: * As of Unicode 3.0.0, the result is limited in the range 0 to 2, as the 1810: * longest uppercase expansion is three characters (a growth of 2 from the 1811: * lowercase character). 1812: * 1813: * @param ch the char to check 1814: * @return the number of characters to add when converting to uppercase 1815: * @see CharData#DIRECTION 1816: * @see CharData#UPPER_SPECIAL 1817: * @see #toUpperCase(Locale) 1818: */ 1819: private static int upperCaseExpansion(char ch) 1820: { 1821: return Character.direction[Character.readChar(ch) >> 7] & 3; 1822: } 1823: 1824: /** 1825: * Helper function used to locate the offset in upperExpand given a 1826: * character with a multi-character expansion. The binary search is 1827: * optimized under the assumption that this method will only be called on 1828: * characters which exist in upperSpecial. 1829: * 1830: * @param ch the char to check 1831: * @return the index where its expansion begins 1832: * @see CharData#UPPER_SPECIAL 1833: * @see CharData#UPPER_EXPAND 1834: * @see #toUpperCase(Locale) 1835: */ 1836: private static int upperCaseIndex(char ch) 1837: { 1838: // Simple binary search for the correct character. 1839: int low = 0; 1840: int hi = upperSpecial.length - 2; 1841: int mid = ((low + hi) >> 2) << 1; 1842: char c = upperSpecial[mid]; 1843: while (ch != c) 1844: { 1845: if (ch < c) 1846: hi = mid - 2; 1847: else 1848: low = mid + 2; 1849: mid = ((low + hi) >> 2) << 1; 1850: c = upperSpecial[mid]; 1851: } 1852: return upperSpecial[mid + 1]; 1853: } 1854: 1855: /** 1856: * Returns the value array of the given string if it is zero based or a 1857: * copy of it that is zero based (stripping offset and making length equal 1858: * to count). Used for accessing the char[]s of gnu.java.lang.CharData. 1859: * Package private for use in Character. 1860: */ 1861: static char[] zeroBasedStringValue(String s) 1862: { 1863: char[] value; 1864: 1865: if (s.offset == 0 && s.count == s.value.length) 1866: value = s.value; 1867: else 1868: { 1869: int count = s.count; 1870: value = new char[count]; 1871: VMSystem.arraycopy(s.value, s.offset, value, 0, count); 1872: } 1873: 1874: return value; 1875: } 1876: }
GNU Classpath (0.19) |