0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.lang;
0019:
0020: import java.io.Serializable;
0021: import java.io.UnsupportedEncodingException;
0022: import java.util.Comparator;
0023: import java.util.Formatter;
0024: import java.util.Locale;
0025:
0026: import java.util.regex.Pattern;
0027:
0028: import java.nio.ByteBuffer;
0029: import java.nio.CharBuffer;
0030: import java.nio.charset.Charset;
0031: import java.nio.charset.IllegalCharsetNameException;
0032: import java.nio.charset.UnsupportedCharsetException;
0033: import java.security.AccessController;
0034: import java.util.regex.PatternSyntaxException;
0035:
0036: import org.apache.harmony.kernel.vm.VM;
0037: import org.apache.harmony.luni.util.PriviAction;
0038:
0039: /**
0040: * <p>
0041: * An immutable sequence of characters/code units (<code>char</code>s). A
0042: * <code>String</code> is represented by array of UTF-16 values, such that
0043: * Unicode supplementary characters (code points) are stored/encoded as
0044: * surrogate pairs via Unicode code units (<code>char</code>)
0045: * </p>
0046: *
0047: * @see StringBuffer
0048: * @see StringBuilder
0049: * @see Charset
0050: * @since 1.0
0051: */
0052: public final class String implements Serializable, Comparable<String>,
0053: CharSequence {
0054:
0055: private static final long serialVersionUID = -6849794470754667710L;
0056:
0057: /**
0058: * An PrintStream used for System.out which performs the correct character
0059: * conversion for the console, since the console may use a different
0060: * conversion than the default file.encoding.
0061: */
0062: static class ConsolePrintStream extends java.io.PrintStream {
0063: private static String charset;
0064:
0065: static {
0066: charset = AccessController
0067: .doPrivileged(new PriviAction<String>(
0068: "console.encoding", "ISO8859_1")); //$NON-NLS-1$ //$NON-NLS-2$
0069: if (!Charset.isSupported(charset)) {
0070: charset = "ISO-8859-1"; //$NON-NLS-1$
0071: }
0072: }
0073:
0074: /**
0075: * Create a ConsolePrintStream on the specified OutputStream, usually
0076: * System.out.
0077: *
0078: * @param out
0079: * the console OutputStream
0080: */
0081: public ConsolePrintStream(java.io.OutputStream out) {
0082: super (out, true);
0083:
0084: }
0085:
0086: /**
0087: * Override the print(String) method from PrintStream to perform the
0088: * character conversion using the console character converter.
0089: *
0090: * @param str
0091: * the String to convert
0092: */
0093: @Override
0094: public void print(String str) {
0095: if (str == null) {
0096: str = "null"; //$NON-NLS-1$
0097: }
0098:
0099: try {
0100: write(str.getBytes(charset));
0101: } catch (java.io.IOException e) {
0102: setError();
0103: }
0104: }
0105: }
0106:
0107: /**
0108: * CaseInsensitiveComparator compares Strings ignoring the case of the
0109: * characters.
0110: */
0111: private static final class CaseInsensitiveComparator implements
0112: Comparator<String>, Serializable {
0113: private static final long serialVersionUID = 8575799808933029326L;
0114:
0115: /**
0116: * Compare the two objects to determine the relative ordering.
0117: *
0118: * @param o1
0119: * an Object to compare
0120: * @param o2
0121: * an Object to compare
0122: * @return an int < 0 if object1 is less than object2, 0 if they are
0123: * equal, and > 0 if object1 is greater
0124: *
0125: * @exception ClassCastException
0126: * when objects are not the correct type
0127: */
0128: public int compare(String o1, String o2) {
0129: return o1.compareToIgnoreCase(o2);
0130: }
0131: }
0132:
0133: /*
0134: * A Comparator which compares Strings ignoring the case of the characters.
0135: */
0136: public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
0137:
0138: private static final char[] ascii;
0139:
0140: private final char[] value;
0141:
0142: private final int offset;
0143:
0144: private final int count;
0145:
0146: private int hashCode;
0147:
0148: private static Charset DefaultCharset;
0149:
0150: private static Charset lastCharset;
0151:
0152: static {
0153: ascii = new char[128];
0154: for (int i = 0; i < ascii.length; i++) {
0155: ascii[i] = (char) i;
0156: }
0157: }
0158:
0159: /**
0160: * Answers an empty string.
0161: */
0162: public String() {
0163: value = new char[0];
0164: offset = 0;
0165: count = 0;
0166: }
0167:
0168: @SuppressWarnings("unused")
0169: private String(String s, char c) {
0170: offset = 0;
0171: value = new char[s.count + 1];
0172: count = s.count + 1;
0173: System.arraycopy(s.value, s.offset, value, 0, s.count);
0174: value[s.count] = c;
0175: }
0176:
0177: /**
0178: * Converts the byte array to a String using the default encoding as
0179: * specified by the file.encoding system property. If the system property is
0180: * not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1
0181: * is not available, an ASCII encoding is used.
0182: *
0183: * @param data
0184: * the byte array to convert to a String
0185: *
0186: * @throws NullPointerException
0187: * when data is null
0188: *
0189: * @see #getBytes()
0190: * @see #getBytes(int, int, byte[], int)
0191: * @see #getBytes(String)
0192: * @see #valueOf(boolean)
0193: * @see #valueOf(char)
0194: * @see #valueOf(char[])
0195: * @see #valueOf(char[], int, int)
0196: * @see #valueOf(double)
0197: * @see #valueOf(float)
0198: * @see #valueOf(int)
0199: * @see #valueOf(long)
0200: * @see #valueOf(Object)
0201: *
0202: */
0203: public String(byte[] data) {
0204: this (data, 0, data.length);
0205: }
0206:
0207: /**
0208: * Converts the byte array to a String, setting the high byte of every
0209: * character to the specified value.
0210: *
0211: * @param data
0212: * the byte array to convert to a String
0213: * @param high
0214: * the high byte to use
0215: *
0216: * @throws NullPointerException
0217: * when data is null
0218: *
0219: * @deprecated Use String(byte[]) or String(byte[], String) instead
0220: */
0221: @Deprecated
0222: public String(byte[] data, int high) {
0223: this (data, high, 0, data.length);
0224: }
0225:
0226: /**
0227: * Converts the byte array to a String using the default encoding as
0228: * specified by the file.encoding system property. If the system property is
0229: * not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1
0230: * is not available, an ASCII encoding is used.
0231: *
0232: * @param data
0233: * the byte array to convert to a String
0234: * @param start
0235: * the starting offset in the byte array
0236: * @param length
0237: * the number of bytes to convert
0238: *
0239: * @throws IndexOutOfBoundsException
0240: * when <code>length < 0, start < 0</code> or
0241: * <code>start + length > data.length</code>
0242: * @throws NullPointerException
0243: * when data is null
0244: *
0245: * @see #getBytes()
0246: * @see #getBytes(int, int, byte[], int)
0247: * @see #getBytes(String)
0248: * @see #valueOf(boolean)
0249: * @see #valueOf(char)
0250: * @see #valueOf(char[])
0251: * @see #valueOf(char[], int, int)
0252: * @see #valueOf(double)
0253: * @see #valueOf(float)
0254: * @see #valueOf(int)
0255: * @see #valueOf(long)
0256: * @see #valueOf(Object)
0257: */
0258: public String(byte[] data, int start, int length) {
0259: // start + length could overflow, start/length maybe MaxInt
0260: if (start >= 0 && 0 <= length && length <= data.length - start) {
0261: offset = 0;
0262: Charset charset = defaultCharset();
0263: int result;
0264: CharBuffer cb = charset.decode(ByteBuffer.wrap(data, start,
0265: length));
0266: if ((result = cb.length()) > 0) {
0267: value = cb.array();
0268: count = result;
0269: } else {
0270: count = 0;
0271: value = new char[0];
0272: }
0273: } else {
0274: throw new StringIndexOutOfBoundsException();
0275: }
0276: }
0277:
0278: /**
0279: * Converts the byte array to a String, setting the high byte of every
0280: * character to the specified value.
0281: *
0282: * @param data
0283: * the byte array to convert to a String
0284: * @param high
0285: * the high byte to use
0286: * @param start
0287: * the starting offset in the byte array
0288: * @param length
0289: * the number of bytes to convert
0290: *
0291: * @throws IndexOutOfBoundsException
0292: * when <code>length < 0, start < 0</code> or
0293: * <code>start + length > data.length</code>
0294: * @throws NullPointerException
0295: * when data is null
0296: *
0297: * @deprecated Use String(byte[], int, int) instead
0298: */
0299: @Deprecated
0300: public String(byte[] data, int high, int start, int length) {
0301: if (data != null) {
0302: // start + length could overflow, start/length maybe MaxInt
0303: if (start >= 0 && 0 <= length
0304: && length <= data.length - start) {
0305: offset = 0;
0306: value = new char[length];
0307: count = length;
0308: high <<= 8;
0309: for (int i = 0; i < count; i++) {
0310: value[i] = (char) (high + (data[start++] & 0xff));
0311: }
0312: } else {
0313: throw new StringIndexOutOfBoundsException();
0314: }
0315: } else {
0316: throw new NullPointerException();
0317: }
0318: }
0319:
0320: /**
0321: * Converts the byte array to a String using the specified encoding.
0322: *
0323: * @param data
0324: * the byte array to convert to a String
0325: * @param start
0326: * the starting offset in the byte array
0327: * @param length
0328: * the number of bytes to convert
0329: * @param encoding
0330: * the encoding
0331: *
0332: * @throws IndexOutOfBoundsException
0333: * when <code>length < 0, start < 0</code> or
0334: * <code>start + length > data.length</code>
0335: * @throws UnsupportedEncodingException
0336: * when encoding is not supported
0337: * @throws NullPointerException
0338: * when data is null
0339: *
0340: * @see #getBytes()
0341: * @see #getBytes(int, int, byte[], int)
0342: * @see #getBytes(String)
0343: * @see #valueOf(boolean)
0344: * @see #valueOf(char)
0345: * @see #valueOf(char[])
0346: * @see #valueOf(char[], int, int)
0347: * @see #valueOf(double)
0348: * @see #valueOf(float)
0349: * @see #valueOf(int)
0350: * @see #valueOf(long)
0351: * @see #valueOf(Object)
0352: * @see UnsupportedEncodingException
0353: */
0354: public String(byte[] data, int start, int length,
0355: final String encoding) throws UnsupportedEncodingException {
0356: if (encoding == null) {
0357: throw new NullPointerException();
0358: }
0359: // start + length could overflow, start/length maybe MaxInt
0360: if (start >= 0 && 0 <= length && length <= data.length - start) {
0361: offset = 0;
0362: Charset charset = getCharset(encoding);
0363:
0364: int result;
0365: CharBuffer cb;
0366: try {
0367: cb = charset.decode(ByteBuffer
0368: .wrap(data, start, length));
0369: } catch (Exception e) {
0370: // do nothing. according to spec:
0371: // behavior is unspecified for invalid array
0372: cb = CharBuffer.wrap("\u003f".toCharArray()); //$NON-NLS-1$
0373: }
0374: if ((result = cb.length()) > 0) {
0375: value = cb.array();
0376: count = result;
0377: } else {
0378: count = 0;
0379: value = new char[0];
0380: }
0381: } else {
0382: throw new StringIndexOutOfBoundsException();
0383: }
0384: }
0385:
0386: /**
0387: * Converts the byte array to a String using the specified encoding.
0388: *
0389: * @param data
0390: * the byte array to convert to a String
0391: * @param encoding
0392: * the encoding
0393: *
0394: * @throws UnsupportedEncodingException
0395: * when encoding is not supported
0396: * @throws NullPointerException
0397: * when data is null
0398: *
0399: * @see #getBytes()
0400: * @see #getBytes(int, int, byte[], int)
0401: * @see #getBytes(String)
0402: * @see #valueOf(boolean)
0403: * @see #valueOf(char)
0404: * @see #valueOf(char[])
0405: * @see #valueOf(char[], int, int)
0406: * @see #valueOf(double)
0407: * @see #valueOf(float)
0408: * @see #valueOf(int)
0409: * @see #valueOf(long)
0410: * @see #valueOf(Object)
0411: * @see UnsupportedEncodingException
0412: */
0413: public String(byte[] data, String encoding)
0414: throws UnsupportedEncodingException {
0415: this (data, 0, data.length, encoding);
0416: }
0417:
0418: /**
0419: * Initializes this String to contain the characters in the specified
0420: * character array. Modifying the character array after creating the String
0421: * has no effect on the String.
0422: *
0423: * @param data
0424: * the array of characters
0425: *
0426: * @throws NullPointerException
0427: * when data is null
0428: */
0429: public String(char[] data) {
0430: this (data, 0, data.length);
0431: }
0432:
0433: /**
0434: * Initializes this String to contain the specified characters in the
0435: * character array. Modifying the character array after creating the String
0436: * has no effect on the String.
0437: *
0438: * @param data
0439: * the array of characters
0440: * @param start
0441: * the starting offset in the character array
0442: * @param length
0443: * the number of characters to use
0444: *
0445: * @throws IndexOutOfBoundsException
0446: * when <code>length < 0, start < 0</code> or
0447: * <code>start + length > data.length</code>
0448: * @throws NullPointerException
0449: * when data is null
0450: */
0451: public String(char[] data, int start, int length) {
0452: // range check everything so a new char[] is not created
0453: // start + length could overflow, start/length maybe MaxInt
0454: if (start >= 0 && 0 <= length && length <= data.length - start) {
0455: offset = 0;
0456: value = new char[length];
0457: count = length;
0458: System.arraycopy(data, start, value, 0, count);
0459: } else {
0460: throw new StringIndexOutOfBoundsException();
0461: }
0462: }
0463:
0464: /*
0465: * Internal version of string constructor. Does not range check, null check,
0466: * or copy the character array.
0467: */
0468: String(int start, int length, char[] data) {
0469: value = data;
0470: offset = start;
0471: count = length;
0472: }
0473:
0474: /**
0475: * Creates a string that is a copy of another string
0476: *
0477: * @param string
0478: * the String to copy
0479: */
0480: public String(String string) {
0481: value = string.value;
0482: offset = string.offset;
0483: count = string.count;
0484: }
0485:
0486: /**
0487: * Creates a string from the contents of a StringBuffer.
0488: *
0489: * @param stringbuffer
0490: * the StringBuffer
0491: */
0492: public String(StringBuffer stringbuffer) {
0493: offset = 0;
0494: synchronized (stringbuffer) {
0495: value = stringbuffer.shareValue();
0496: count = stringbuffer.length();
0497: }
0498: }
0499:
0500: /**
0501: * <p>
0502: * Constructs a <code>String</code> from the sub-array of Unicode code
0503: * points.
0504: * </p>
0505: *
0506: * @param codePoints
0507: * The array of Unicode code points to convert.
0508: * @param offset
0509: * The inclusive index into <code>codePoints</code> to begin
0510: * converting from.
0511: * @param count
0512: * The number of element in <code>codePoints</code> to copy.
0513: * @throws NullPointerException
0514: * if <code>codePoints</code> is null.
0515: * @throws IllegalArgumentException
0516: * if any of the elements of <code>codePoints</code> are not
0517: * valid Unicode code points.
0518: * @throws IndexOutOfBoundsException
0519: * if <code>offset</code> or <code>count</code> are not
0520: * within the bounds of <code>codePoints</code>.
0521: * @since 1.5
0522: */
0523: public String(int[] codePoints, int offset, int count) {
0524: super ();
0525: if (codePoints == null) {
0526: throw new NullPointerException();
0527: }
0528: if (offset < 0 || count < 0
0529: || (long) offset + (long) count > codePoints.length) {
0530: throw new IndexOutOfBoundsException();
0531: }
0532: this .offset = 0;
0533: this .value = new char[count * 2];
0534: int end = offset + count;
0535: int c = 0;
0536: for (int i = offset; i < end; i++) {
0537: c += Character.toChars(codePoints[i], this .value, c);
0538: }
0539: this .count = c;
0540: }
0541:
0542: /**
0543: * <p>
0544: * Constructs a <code>String</code> from a <code>StringBuilder</code>.
0545: * </p>
0546: *
0547: * @param sb
0548: * The StringBuilder to copy from.
0549: * @throws NullPointerException
0550: * if <code>sb</code> is <code>null</code>.
0551: * @since 1.5
0552: */
0553: public String(StringBuilder sb) {
0554: if (sb == null) {
0555: throw new NullPointerException();
0556: }
0557: this .offset = 0;
0558: this .count = sb.length();
0559: this .value = new char[this .count];
0560: sb.getChars(0, this .count, this .value, 0);
0561: }
0562:
0563: /*
0564: * Creates a string that is s1 + v1. May be used by JIT code.
0565: */
0566: @SuppressWarnings("unused")
0567: private String(String s1, int v1) {
0568: if (s1 == null) {
0569: s1 = "null"; //$NON-NLS-1$
0570: }
0571: String s2 = String.valueOf(v1);
0572: int len = s1.count + s2.count;
0573: value = new char[len];
0574: offset = 0;
0575: System.arraycopy(s1.value, s1.offset, value, 0, s1.count);
0576: System
0577: .arraycopy(s2.value, s2.offset, value, s1.count,
0578: s2.count);
0579: count = len;
0580: }
0581:
0582: /**
0583: * Answers the character at the specified offset in this String.
0584: *
0585: * @param index
0586: * the zero-based index in this string
0587: * @return the character at the index
0588: *
0589: * @throws IndexOutOfBoundsException
0590: * when <code>index < 0</code> or
0591: * <code>index >= length()</code>
0592: */
0593: public char charAt(int index) {
0594: if (0 <= index && index < count) {
0595: return value[offset + index];
0596: }
0597: throw new StringIndexOutOfBoundsException();
0598: }
0599:
0600: /**
0601: * Compares the specified String to this String using the Unicode values of
0602: * the characters. Answer 0 if the strings contain the same characters in
0603: * the same order. Answer a negative integer if the first non-equal
0604: * character in this String has a Unicode value which is less than the
0605: * Unicode value of the character at the same position in the specified
0606: * string, or if this String is a prefix of the specified string. Answer a
0607: * positive integer if the first non-equal character in this String has a
0608: * Unicode value which is greater than the Unicode value of the character at
0609: * the same position in the specified string, or if the specified String is
0610: * a prefix of the this String.
0611: *
0612: * @param string
0613: * the string to compare
0614: * @return 0 if the strings are equal, a negative integer if this String is
0615: * before the specified String, or a positive integer if this String
0616: * is after the specified String
0617: *
0618: * @throws NullPointerException
0619: * when string is null
0620: */
0621: public int compareTo(String string) {
0622: // Code adapted from K&R, pg 101
0623: int o1 = offset, o2 = string.offset, result;
0624: int end = offset
0625: + (count < string.count ? count : string.count);
0626: char[] target = string.value;
0627: while (o1 < end) {
0628: if ((result = value[o1++] - target[o2++]) != 0) {
0629: return result;
0630: }
0631: }
0632: return count - string.count;
0633: }
0634:
0635: /**
0636: * Compare the receiver to the specified String to determine the relative
0637: * ordering when the case of the characters is ignored.
0638: *
0639: * @param string
0640: * a String
0641: * @return an int < 0 if this String is less than the specified String, 0 if
0642: * they are equal, and > 0 if this String is greater
0643: */
0644: public int compareToIgnoreCase(String string) {
0645: int o1 = offset, o2 = string.offset, result;
0646: int end = offset
0647: + (count < string.count ? count : string.count);
0648: char c1, c2;
0649: char[] target = string.value;
0650: while (o1 < end) {
0651: if ((c1 = value[o1++]) == (c2 = target[o2++])) {
0652: continue;
0653: }
0654: c1 = Character.toLowerCase(Character.toUpperCase(c1));
0655: c2 = Character.toLowerCase(Character.toUpperCase(c2));
0656: if ((result = c1 - c2) != 0) {
0657: return result;
0658: }
0659: }
0660: return count - string.count;
0661: }
0662:
0663: /**
0664: * Concatenates this String and the specified string.
0665: *
0666: * @param string
0667: * the string to concatenate
0668: * @return a new String which is the concatenation of this String and the
0669: * specified String
0670: *
0671: * @throws NullPointerException
0672: * if string is null
0673: */
0674: public String concat(String string) {
0675: if (string.count > 0 && count > 0) {
0676: char[] buffer = new char[count + string.count];
0677: System.arraycopy(value, offset, buffer, 0, count);
0678: System.arraycopy(string.value, string.offset, buffer,
0679: count, string.count);
0680: return new String(0, buffer.length, buffer);
0681: }
0682: return count == 0 ? string : this ;
0683: }
0684:
0685: /**
0686: * Creates a new String containing the characters in the specified character
0687: * array. Modifying the character array after creating the String has no
0688: * effect on the String.
0689: *
0690: * @param data
0691: * the array of characters
0692: * @return the new String
0693: *
0694: * @throws NullPointerException
0695: * if data is null
0696: */
0697: public static String copyValueOf(char[] data) {
0698: return new String(data, 0, data.length);
0699: }
0700:
0701: /**
0702: * Creates a new String containing the specified characters in the character
0703: * array. Modifying the character array after creating the String has no
0704: * effect on the String.
0705: *
0706: * @param data
0707: * the array of characters
0708: * @param start
0709: * the starting offset in the character array
0710: * @param length
0711: * the number of characters to use
0712: * @return the new String
0713: *
0714: * @throws IndexOutOfBoundsException
0715: * if <code>length < 0, start < 0</code> or
0716: * <code>start + length > data.length</code>
0717: * @throws NullPointerException
0718: * if data is null
0719: */
0720: public static String copyValueOf(char[] data, int start, int length) {
0721: return new String(data, start, length);
0722: }
0723:
0724: private Charset defaultCharset() {
0725: if (DefaultCharset == null) {
0726: String encoding = AccessController
0727: .doPrivileged(new PriviAction<String>(
0728: "file.encoding", "ISO8859_1")); //$NON-NLS-1$ //$NON-NLS-2$
0729: // calling System.getProperty() may cause DefaultCharset to be
0730: // initialized
0731: try {
0732: DefaultCharset = Charset.forName(encoding);
0733: } catch (IllegalCharsetNameException e) {
0734: // Ignored
0735: } catch (UnsupportedCharsetException e) {
0736: // Ignored
0737: }
0738:
0739: if (DefaultCharset == null) {
0740: DefaultCharset = Charset.forName("ISO-8859-1"); //$NON-NLS-1$
0741: }
0742: }
0743: return DefaultCharset;
0744: }
0745:
0746: /**
0747: * Compares the specified string to this String to determine if the
0748: * specified string is a suffix.
0749: *
0750: * @param suffix
0751: * the string to look for
0752: * @return true when the specified string is a suffix of this String, false
0753: * otherwise
0754: *
0755: * @throws NullPointerException
0756: * if suffix is null
0757: */
0758: public boolean endsWith(String suffix) {
0759: return regionMatches(count - suffix.count, suffix, 0,
0760: suffix.count);
0761: }
0762:
0763: /**
0764: * Compares the specified object to this String and answer if they are
0765: * equal. The object must be an instance of String with the same characters
0766: * in the same order.
0767: *
0768: * @param object
0769: * the object to compare
0770: * @return true if the specified object is equal to this String, false
0771: * otherwise
0772: *
0773: * @see #hashCode
0774: */
0775: @Override
0776: public boolean equals(Object object) {
0777: if (object == this ) {
0778: return true;
0779: }
0780: if (object instanceof String) {
0781: String s = (String) object;
0782: if (count != s.count
0783: || (hashCode != s.hashCode && hashCode != 0 && s.hashCode != 0)) {
0784: return false;
0785: }
0786: return regionMatches(0, s, 0, count);
0787: }
0788: return false;
0789: }
0790:
0791: /**
0792: * Compares the specified String to this String ignoring the case of the
0793: * characters and answer if they are equal.
0794: *
0795: * @param string
0796: * the string to compare
0797: * @return true if the specified string is equal to this String, false
0798: * otherwise
0799: */
0800: public boolean equalsIgnoreCase(String string) {
0801: if (string == this ) {
0802: return true;
0803: }
0804: if (string == null || count != string.count) {
0805: return false;
0806: }
0807:
0808: int o1 = offset, o2 = string.offset;
0809: int end = offset + count;
0810: char c1, c2;
0811: char[] target = string.value;
0812: while (o1 < end) {
0813: if ((c1 = value[o1++]) != (c2 = target[o2++])
0814: && Character.toUpperCase(c1) != Character
0815: .toUpperCase(c2)
0816: // Required for unicode that we test both cases
0817: && Character.toLowerCase(c1) != Character
0818: .toLowerCase(c2)) {
0819: return false;
0820: }
0821: }
0822: return true;
0823: }
0824:
0825: /**
0826: * Converts this String to a byte encoding using the default encoding as
0827: * specified by the file.encoding system property. If the system property is
0828: * not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1
0829: * is not available, an ASCII encoding is used.
0830: *
0831: * @return the byte array encoding of this String
0832: *
0833: * @see String
0834: */
0835: public byte[] getBytes() {
0836: ByteBuffer buffer = defaultCharset().encode(
0837: CharBuffer.wrap(this .value, this .offset, this .count));
0838: byte[] bytes = new byte[buffer.limit()];
0839: buffer.get(bytes);
0840: return bytes;
0841: }
0842:
0843: /**
0844: * Converts this String to a byte array, ignoring the high order bits of
0845: * each character.
0846: *
0847: * @param start
0848: * the starting offset of characters to copy
0849: * @param end
0850: * the ending offset of characters to copy
0851: * @param data
0852: * the destination byte array
0853: * @param index
0854: * the starting offset in the byte array
0855: *
0856: * @throws NullPointerException
0857: * when data is null
0858: * @throws IndexOutOfBoundsException
0859: * when
0860: * <code>start < 0, end > length(), index < 0, end - start > data.length - index</code>
0861: *
0862: * @deprecated Use getBytes() or getBytes(String)
0863: */
0864: @Deprecated
0865: public void getBytes(int start, int end, byte[] data, int index) {
0866: if (0 <= start && start <= end && end <= count) {
0867: end += offset;
0868: try {
0869: for (int i = offset + start; i < end; i++) {
0870: data[index++] = (byte) value[i];
0871: }
0872: } catch (ArrayIndexOutOfBoundsException e) {
0873: throw new StringIndexOutOfBoundsException();
0874: }
0875: } else {
0876: throw new StringIndexOutOfBoundsException();
0877: }
0878: }
0879:
0880: /**
0881: * Converts this String to a byte encoding using the specified encoding.
0882: *
0883: * @param encoding
0884: * the encoding
0885: * @return the byte array encoding of this String
0886: *
0887: * @throws UnsupportedEncodingException
0888: * when the encoding is not supported
0889: *
0890: * @see String
0891: * @see UnsupportedEncodingException
0892: */
0893: public byte[] getBytes(String encoding)
0894: throws UnsupportedEncodingException {
0895: ByteBuffer buffer = getCharset(encoding).encode(
0896: CharBuffer.wrap(this .value, this .offset, this .count));
0897: byte[] bytes = new byte[buffer.limit()];
0898: buffer.get(bytes);
0899: return bytes;
0900: }
0901:
0902: private Charset getCharset(final String encoding)
0903: throws UnsupportedEncodingException {
0904: Charset charset = lastCharset;
0905: if (charset == null
0906: || !encoding.equalsIgnoreCase(charset.name())) {
0907: try {
0908: charset = Charset.forName(encoding);
0909: } catch (IllegalCharsetNameException e) {
0910: throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
0911: encoding).initCause(e));
0912: } catch (UnsupportedCharsetException e) {
0913: throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
0914: encoding).initCause(e));
0915: }
0916: lastCharset = charset;
0917: }
0918: return charset;
0919: }
0920:
0921: /**
0922: * Copies the specified characters in this String to the character array
0923: * starting at the specified offset in the character array.
0924: *
0925: * @param start
0926: * the starting offset of characters to copy
0927: * @param end
0928: * the ending offset of characters to copy
0929: * @param buffer
0930: * the destination character array
0931: * @param index
0932: * the starting offset in the character array
0933: *
0934: * @throws IndexOutOfBoundsException
0935: * when <code>start < 0, end > length(),
0936: * start > end, index < 0, end - start > buffer.length - index</code>
0937: * @throws NullPointerException
0938: * when buffer is null
0939: */
0940: public void getChars(int start, int end, char[] buffer, int index) {
0941: // NOTE last character not copied!
0942: // Fast range check.
0943: if (0 <= start && start <= end && end <= count) {
0944: System.arraycopy(value, start + offset, buffer, index, end
0945: - start);
0946: } else {
0947: throw new StringIndexOutOfBoundsException();
0948: }
0949: }
0950:
0951: /**
0952: * Answers an integer hash code for the receiver. Objects which are equal
0953: * answer the same value for this method.
0954: *
0955: * @return the receiver's hash
0956: *
0957: * @see #equals
0958: */
0959: @Override
0960: public int hashCode() {
0961: if (hashCode == 0) {
0962: int hash = 0, multiplier = 1;
0963: for (int i = offset + count - 1; i >= offset; i--) {
0964: hash += value[i] * multiplier;
0965: int shifted = multiplier << 5;
0966: multiplier = shifted - multiplier;
0967: }
0968: hashCode = hash;
0969: }
0970: return hashCode;
0971: }
0972:
0973: /**
0974: * Searches in this String for the first index of the specified character.
0975: * The search for the character starts at the beginning and moves towards
0976: * the end of this String.
0977: *
0978: * @param c
0979: * the character to find
0980: * @return the index in this String of the specified character, -1 if the
0981: * character isn't found
0982: *
0983: * @see #lastIndexOf(int)
0984: * @see #lastIndexOf(int, int)
0985: * @see #lastIndexOf(String)
0986: * @see #lastIndexOf(String, int)
0987: */
0988: public int indexOf(int c) {
0989: return indexOf(c, 0);
0990: }
0991:
0992: /**
0993: * Searches in this String for the index of the specified character. The
0994: * search for the character starts at the specified offset and moves towards
0995: * the end of this String.
0996: *
0997: * @param c
0998: * the character to find
0999: * @param start
1000: * the starting offset
1001: * @return the index in this String of the specified character, -1 if the
1002: * character isn't found
1003: *
1004: * @see #lastIndexOf(int)
1005: * @see #lastIndexOf(int, int)
1006: * @see #lastIndexOf(String)
1007: * @see #lastIndexOf(String, int)
1008: */
1009: public int indexOf(int c, int start) {
1010: if (start < count) {
1011: if (start < 0) {
1012: start = 0;
1013: }
1014: for (int i = offset + start; i < offset + count; i++) {
1015: if (value[i] == c) {
1016: return i - offset;
1017: }
1018: }
1019: }
1020: return -1;
1021: }
1022:
1023: /**
1024: * Searches in this String for the first index of the specified string. The
1025: * search for the string starts at the beginning and moves towards the end
1026: * of this String.
1027: *
1028: * @param string
1029: * the string to find
1030: * @return the index in this String of the specified string, -1 if the
1031: * string isn't found
1032: *
1033: * @throws NullPointerException
1034: * when string is null
1035: *
1036: * @see #lastIndexOf(int)
1037: * @see #lastIndexOf(int, int)
1038: * @see #lastIndexOf(String)
1039: * @see #lastIndexOf(String, int)
1040: */
1041: public int indexOf(String string) {
1042: return indexOf(string, 0);
1043: }
1044:
1045: /**
1046: * Searches in this String for the index of the specified string. The search
1047: * for the string starts at the specified offset and moves towards the end
1048: * of this String.
1049: *
1050: * @param subString
1051: * the string to find
1052: * @param start
1053: * the starting offset
1054: * @return the index in this String of the specified string, -1 if the
1055: * string isn't found
1056: *
1057: * @throws NullPointerException
1058: * when string is null
1059: *
1060: * @see #lastIndexOf(int)
1061: * @see #lastIndexOf(int, int)
1062: * @see #lastIndexOf(String)
1063: * @see #lastIndexOf(String, int)
1064: */
1065: public int indexOf(String subString, int start) {
1066: if (start < 0) {
1067: start = 0;
1068: }
1069: int subCount = subString.count;
1070: if (subCount > 0) {
1071: if (subCount + start > count) {
1072: return -1;
1073: }
1074: char[] target = subString.value;
1075: int subOffset = subString.offset;
1076: char firstChar = target[subOffset];
1077: int end = subOffset + subCount;
1078: while (true) {
1079: int i = indexOf(firstChar, start);
1080: if (i == -1 || subCount + i > count) {
1081: return -1; // handles subCount > count || start >= count
1082: }
1083: int o1 = offset + i, o2 = subOffset;
1084: while (++o2 < end && value[++o1] == target[o2]) {
1085: // Intentionally empty
1086: }
1087: if (o2 == end) {
1088: return i;
1089: }
1090: start = i + 1;
1091: }
1092: }
1093: return start < count ? start : count;
1094: }
1095:
1096: /**
1097: * Searches an internal table of strings for a string equal to this String.
1098: * If the string is not in the table, it is added. Answers the string
1099: * contained in the table which is equal to this String. The same string
1100: * object is always answered for strings which are equal.
1101: *
1102: * @return the interned string equal to this String
1103: */
1104: public String intern() {
1105: return VM.intern(this );
1106: }
1107:
1108: /**
1109: * Searches in this String for the last index of the specified character.
1110: * The search for the character starts at the end and moves towards the
1111: * beginning of this String.
1112: *
1113: * @param c
1114: * the character to find
1115: * @return the index in this String of the specified character, -1 if the
1116: * character isn't found
1117: *
1118: * @see #lastIndexOf(int)
1119: * @see #lastIndexOf(int, int)
1120: * @see #lastIndexOf(String)
1121: * @see #lastIndexOf(String, int)
1122: */
1123: public int lastIndexOf(int c) {
1124: return lastIndexOf(c, count - 1);
1125: }
1126:
1127: /**
1128: * Searches in this String for the index of the specified character. The
1129: * search for the character starts at the specified offset and moves towards
1130: * the beginning of this String.
1131: *
1132: * @param c
1133: * the character to find
1134: * @param start
1135: * the starting offset
1136: * @return the index in this String of the specified character, -1 if the
1137: * character isn't found
1138: *
1139: * @see #lastIndexOf(int)
1140: * @see #lastIndexOf(int, int)
1141: * @see #lastIndexOf(String)
1142: * @see #lastIndexOf(String, int)
1143: */
1144: public int lastIndexOf(int c, int start) {
1145: if (start >= 0) {
1146: if (start >= count) {
1147: start = count - 1;
1148: }
1149: for (int i = offset + start; i >= offset; --i) {
1150: if (value[i] == c) {
1151: return i - offset;
1152: }
1153: }
1154: }
1155: return -1;
1156: }
1157:
1158: /**
1159: * Searches in this String for the last index of the specified string. The
1160: * search for the string starts at the end and moves towards the beginning
1161: * of this String.
1162: *
1163: * @param string
1164: * the string to find
1165: * @return the index in this String of the specified string, -1 if the
1166: * string isn't found
1167: *
1168: * @throws NullPointerException
1169: * when string is null
1170: *
1171: * @see #lastIndexOf(int)
1172: * @see #lastIndexOf(int, int)
1173: * @see #lastIndexOf(String)
1174: * @see #lastIndexOf(String, int)
1175: */
1176: public int lastIndexOf(String string) {
1177: // Use count instead of count - 1 so lastIndexOf("") answers count
1178: return lastIndexOf(string, count);
1179: }
1180:
1181: /**
1182: * Searches in this String for the index of the specified string. The search
1183: * for the string starts at the specified offset and moves towards the
1184: * beginning of this String.
1185: *
1186: * @param subString
1187: * the string to find
1188: * @param start
1189: * the starting offset
1190: * @return the index in this String of the specified string, -1 if the
1191: * string isn't found
1192: *
1193: * @throws NullPointerException
1194: * when string is null
1195: *
1196: * @see #lastIndexOf(int)
1197: * @see #lastIndexOf(int, int)
1198: * @see #lastIndexOf(String)
1199: * @see #lastIndexOf(String, int)
1200: */
1201: public int lastIndexOf(String subString, int start) {
1202: int subCount = subString.count;
1203: if (subCount <= count && start >= 0) {
1204: if (subCount > 0) {
1205: if (start > count - subCount) {
1206: start = count - subCount;
1207: }
1208: // count and subCount are both >= 1
1209: char[] target = subString.value;
1210: int subOffset = subString.offset;
1211: char firstChar = target[subOffset];
1212: int end = subOffset + subCount;
1213: while (true) {
1214: int i = lastIndexOf(firstChar, start);
1215: if (i == -1) {
1216: return -1;
1217: }
1218: int o1 = offset + i, o2 = subOffset;
1219: while (++o2 < end && value[++o1] == target[o2]) {
1220: // Intentionally empty
1221: }
1222: if (o2 == end) {
1223: return i;
1224: }
1225: start = i - 1;
1226: }
1227: }
1228: return start < count ? start : count;
1229: }
1230: return -1;
1231: }
1232:
1233: /**
1234: * Answers the size of this String.
1235: *
1236: * @return the number of characters in this String
1237: */
1238: public int length() {
1239: return count;
1240: }
1241:
1242: /**
1243: * Compares the specified string to this String and compares the specified
1244: * range of characters to determine if they are the same.
1245: *
1246: * @param thisStart
1247: * the starting offset in this String
1248: * @param string
1249: * the string to compare
1250: * @param start
1251: * the starting offset in string
1252: * @param length
1253: * the number of characters to compare
1254: * @return true if the ranges of characters is equal, false otherwise
1255: *
1256: * @throws NullPointerException
1257: * when string is null
1258: */
1259: public boolean regionMatches(int this Start, String string,
1260: int start, int length) {
1261: if (string == null) {
1262: throw new NullPointerException();
1263: }
1264: if (start < 0 || string.count - start < length) {
1265: return false;
1266: }
1267: if (this Start < 0 || count - this Start < length) {
1268: return false;
1269: }
1270: if (length <= 0) {
1271: return true;
1272: }
1273: int o1 = offset + this Start, o2 = string.offset + start;
1274: for (int i = 0; i < length; ++i) {
1275: if (value[o1 + i] != string.value[o2 + i]) {
1276: return false;
1277: }
1278: }
1279: return true;
1280: }
1281:
1282: /**
1283: * Compares the specified string to this String and compares the specified
1284: * range of characters to determine if they are the same. When ignoreCase is
1285: * true, the case of the characters is ignored during the comparison.
1286: *
1287: * @param ignoreCase
1288: * specifies if case should be ignored
1289: * @param thisStart
1290: * the starting offset in this String
1291: * @param string
1292: * the string to compare
1293: * @param start
1294: * the starting offset in string
1295: * @param length
1296: * the number of characters to compare
1297: * @return true if the ranges of characters is equal, false otherwise
1298: *
1299: * @throws NullPointerException
1300: * when string is null
1301: */
1302: public boolean regionMatches(boolean ignoreCase, int this Start,
1303: String string, int start, int length) {
1304: if (!ignoreCase) {
1305: return regionMatches(this Start, string, start, length);
1306: }
1307:
1308: if (string != null) {
1309: if (this Start < 0 || length > count - this Start) {
1310: return false;
1311: }
1312: if (start < 0 || length > string.count - start) {
1313: return false;
1314: }
1315:
1316: this Start += offset;
1317: start += string.offset;
1318: int end = this Start + length;
1319: char c1, c2;
1320: char[] target = string.value;
1321: while (this Start < end) {
1322: if ((c1 = value[this Start++]) != (c2 = target[start++])
1323: && Character.toUpperCase(c1) != Character
1324: .toUpperCase(c2)
1325: // Required for unicode that we test both cases
1326: && Character.toLowerCase(c1) != Character
1327: .toLowerCase(c2)) {
1328: return false;
1329: }
1330: }
1331: return true;
1332: }
1333: throw new NullPointerException();
1334: }
1335:
1336: /**
1337: * Copies this String replacing occurrences of the specified character with
1338: * another character.
1339: *
1340: * @param oldChar
1341: * the character to replace
1342: * @param newChar
1343: * the replacement character
1344: * @return a new String with occurrences of oldChar replaced by newChar
1345: */
1346: public String replace(char oldChar, char newChar) {
1347: int index = indexOf(oldChar, 0);
1348: if (index == -1) {
1349: return this ;
1350: }
1351:
1352: char[] buffer = new char[count];
1353: System.arraycopy(value, offset, buffer, 0, count);
1354: do {
1355: buffer[index++] = newChar;
1356: } while ((index = indexOf(oldChar, index)) != -1);
1357: return new String(0, count, buffer);
1358: }
1359:
1360: /**
1361: * Copies this String replacing occurrences of the specified
1362: * target sequence with another sequence.
1363: * The string is processed from the beginning to the end.
1364: *
1365: * @param target
1366: * the sequence to replace
1367: * @param replacement
1368: * the replacement sequence
1369: * @return the resulting String
1370: *
1371: * @throws NullPointerException if either of the arguments
1372: * is <code>null</code>
1373: */
1374: public String replace(CharSequence target, CharSequence replacement) {
1375: if (target == null) {
1376: throw new NullPointerException("target should not be null");
1377: }
1378: if (replacement == null) {
1379: throw new NullPointerException(
1380: "replacement should not be null");
1381: }
1382: String ts = target.toString();
1383: int index = indexOf(ts, 0);
1384:
1385: if (index == -1)
1386: return this ;
1387:
1388: String rs = replacement.toString();
1389: StringBuilder buffer = new StringBuilder(count);
1390: int tl = target.length();
1391: int tail = 0;
1392: do {
1393: buffer.append(value, offset + tail, index - tail);
1394: buffer.append(rs);
1395: tail = index + tl;
1396: } while ((index = indexOf(ts, tail)) != -1);
1397: //append trailing chars
1398: buffer.append(value, offset + tail, count - tail);
1399:
1400: return buffer.toString();
1401: }
1402:
1403: /**
1404: * Compares the specified string to this String to determine if the
1405: * specified string is a prefix.
1406: *
1407: * @param prefix
1408: * the string to look for
1409: * @return true when the specified string is a prefix of this String, false
1410: * otherwise
1411: *
1412: * @throws NullPointerException
1413: * when prefix is null
1414: */
1415: public boolean startsWith(String prefix) {
1416: return startsWith(prefix, 0);
1417: }
1418:
1419: /**
1420: * Compares the specified string to this String, starting at the specified
1421: * offset, to determine if the specified string is a prefix.
1422: *
1423: * @param prefix
1424: * the string to look for
1425: * @param start
1426: * the starting offset
1427: * @return true when the specified string occurs in this String at the
1428: * specified offset, false otherwise
1429: *
1430: * @throws NullPointerException
1431: * when prefix is null
1432: */
1433: public boolean startsWith(String prefix, int start) {
1434: return regionMatches(start, prefix, 0, prefix.count);
1435: }
1436:
1437: /**
1438: * Copies a range of characters into a new String.
1439: *
1440: * @param start
1441: * the offset of the first character
1442: * @return a new String containing the characters from start to the end of
1443: * the string
1444: *
1445: * @throws IndexOutOfBoundsException
1446: * when <code>start < 0</code> or
1447: * <code>start > length()</code>
1448: */
1449: public String substring(int start) {
1450: if (start == 0) {
1451: return this ;
1452: }
1453: if (0 <= start && start <= count) {
1454: return new String(offset + start, count - start, value);
1455: }
1456: throw new StringIndexOutOfBoundsException(start);
1457: }
1458:
1459: /**
1460: * Copies a range of characters into a new String.
1461: *
1462: * @param start
1463: * the offset of the first character
1464: * @param end
1465: * the offset one past the last character
1466: * @return a new String containing the characters from start to end - 1
1467: *
1468: * @throws IndexOutOfBoundsException
1469: * when <code>start < 0, start > end</code> or
1470: * <code>end > length()</code>
1471: */
1472: public String substring(int start, int end) {
1473: if (start == 0 && end == count) {
1474: return this ;
1475: }
1476: // NOTE last character not copied!
1477: // Fast range check.
1478: if (0 <= start && start <= end && end <= count) {
1479: return new String(offset + start, end - start, value);
1480: }
1481: throw new StringIndexOutOfBoundsException();
1482: }
1483:
1484: /**
1485: * Copies the characters in this String to a character array.
1486: *
1487: * @return a character array containing the characters of this String
1488: */
1489: public char[] toCharArray() {
1490: char[] buffer = new char[count];
1491: System.arraycopy(value, offset, buffer, 0, count);
1492: return buffer;
1493: }
1494:
1495: /**
1496: * Converts the characters in this String to lowercase, using the default
1497: * Locale.
1498: *
1499: * @return a new String containing the lowercase characters equivalent to
1500: * the characters in this String
1501: */
1502: public String toLowerCase() {
1503: return toLowerCase(Locale.getDefault());
1504: }
1505:
1506: /**
1507: * Converts the characters in this String to lowercase, using the specified
1508: * Locale.
1509: *
1510: * @param locale
1511: * the Locale
1512: * @return a new String containing the lowercase characters equivalent to
1513: * the characters in this String
1514: */
1515: public String toLowerCase(Locale locale) {
1516: for (int o = offset, end = offset + count; o < end; o++) {
1517: char ch = value[o];
1518: if (ch != Character.toLowerCase(ch)) {
1519: char[] buffer = new char[count];
1520: int i = o - offset;
1521: // Not worth checking for i == 0 case
1522: System.arraycopy(value, offset, buffer, 0, i);
1523: // Turkish
1524: if (!"tr".equals(locale.getLanguage())) { //$NON-NLS-1$
1525: while (i < count) {
1526: buffer[i++] = Character.toLowerCase(value[o++]);
1527: }
1528: } else {
1529: while (i < count) {
1530: buffer[i++] = (ch = value[o++]) != 0x49 ? Character
1531: .toLowerCase(ch)
1532: : (char) 0x131;
1533: }
1534: }
1535: return new String(0, count, buffer);
1536: }
1537: }
1538: return this ;
1539: }
1540:
1541: /**
1542: * Answers a string containing a concise, human-readable description of the
1543: * receiver.
1544: *
1545: * @return this String
1546: */
1547: @Override
1548: public String toString() {
1549: return this ;
1550: }
1551:
1552: /**
1553: * Converts the characters in this String to uppercase, using the default
1554: * Locale.
1555: *
1556: * @return a new String containing the uppercase characters equivalent to
1557: * the characters in this String
1558: */
1559: public String toUpperCase() {
1560: return toUpperCase(Locale.getDefault());
1561: }
1562:
1563: private static final char[] upperValues = "SS\u0000\u02bcN\u0000J\u030c\u0000\u0399\u0308\u0301\u03a5\u0308\u0301\u0535\u0552\u0000H\u0331\u0000T\u0308\u0000W\u030a\u0000Y\u030a\u0000A\u02be\u0000\u03a5\u0313\u0000\u03a5\u0313\u0300\u03a5\u0313\u0301\u03a5\u0313\u0342\u1f08\u0399\u0000\u1f09\u0399\u0000\u1f0a\u0399\u0000\u1f0b\u0399\u0000\u1f0c\u0399\u0000\u1f0d\u0399\u0000\u1f0e\u0399\u0000\u1f0f\u0399\u0000\u1f08\u0399\u0000\u1f09\u0399\u0000\u1f0a\u0399\u0000\u1f0b\u0399\u0000\u1f0c\u0399\u0000\u1f0d\u0399\u0000\u1f0e\u0399\u0000\u1f0f\u0399\u0000\u1f28\u0399\u0000\u1f29\u0399\u0000\u1f2a\u0399\u0000\u1f2b\u0399\u0000\u1f2c\u0399\u0000\u1f2d\u0399\u0000\u1f2e\u0399\u0000\u1f2f\u0399\u0000\u1f28\u0399\u0000\u1f29\u0399\u0000\u1f2a\u0399\u0000\u1f2b\u0399\u0000\u1f2c\u0399\u0000\u1f2d\u0399\u0000\u1f2e\u0399\u0000\u1f2f\u0399\u0000\u1f68\u0399\u0000\u1f69\u0399\u0000\u1f6a\u0399\u0000\u1f6b\u0399\u0000\u1f6c\u0399\u0000\u1f6d\u0399\u0000\u1f6e\u0399\u0000\u1f6f\u0399\u0000\u1f68\u0399\u0000\u1f69\u0399\u0000\u1f6a\u0399\u0000\u1f6b\u0399\u0000\u1f6c\u0399\u0000\u1f6d\u0399\u0000\u1f6e\u0399\u0000\u1f6f\u0399\u0000\u1fba\u0399\u0000\u0391\u0399\u0000\u0386\u0399\u0000\u0391\u0342\u0000\u0391\u0342\u0399\u0391\u0399\u0000\u1fca\u0399\u0000\u0397\u0399\u0000\u0389\u0399\u0000\u0397\u0342\u0000\u0397\u0342\u0399\u0397\u0399\u0000\u0399\u0308\u0300\u0399\u0308\u0301\u0399\u0342\u0000\u0399\u0308\u0342\u03a5\u0308\u0300\u03a5\u0308\u0301\u03a1\u0313\u0000\u03a5\u0342\u0000\u03a5\u0308\u0342\u1ffa\u0399\u0000\u03a9\u0399\u0000\u038f\u0399\u0000\u03a9\u0342\u0000\u03a9\u0342\u0399\u03a9\u0399\u0000FF\u0000FI\u0000FL\u0000FFIFFLST\u0000ST\u0000\u0544\u0546\u0000\u0544\u0535\u0000\u0544\u053b\u0000\u054e\u0546\u0000\u0544\u053d\u0000".value; //$NON-NLS-1$
1564:
1565: /**
1566: * Return the index of the specified character into the upperValues table.
1567: * The upperValues table contains three entries at each position. These
1568: * three characters are the upper case conversion. If only two characters
1569: * are used, the third character in the table is \u0000.
1570: *
1571: * @param ch
1572: * the char being converted to upper case
1573: *
1574: * @return the index into the upperValues table, or -1
1575: */
1576: private int upperIndex(int ch) {
1577: int index = -1;
1578: if (ch >= 0xdf) {
1579: if (ch <= 0x587) {
1580: if (ch == 0xdf) {
1581: index = 0;
1582: } else if (ch <= 0x149) {
1583: if (ch == 0x149) {
1584: index = 1;
1585: }
1586: } else if (ch <= 0x1f0) {
1587: if (ch == 0x1f0) {
1588: index = 2;
1589: }
1590: } else if (ch <= 0x390) {
1591: if (ch == 0x390) {
1592: index = 3;
1593: }
1594: } else if (ch <= 0x3b0) {
1595: if (ch == 0x3b0) {
1596: index = 4;
1597: }
1598: } else if (ch <= 0x587) {
1599: if (ch == 0x587) {
1600: index = 5;
1601: }
1602: }
1603: } else if (ch >= 0x1e96) {
1604: if (ch <= 0x1e9a) {
1605: index = 6 + ch - 0x1e96;
1606: } else if (ch >= 0x1f50 && ch <= 0x1ffc) {
1607: index = "\u000b\u0000\f\u0000\r\u0000\u000e\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>\u0000\u0000?@A\u0000BC\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0000\u0000EFG\u0000HI\u0000\u0000\u0000\u0000J\u0000\u0000\u0000\u0000\u0000KL\u0000\u0000MN\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000OPQ\u0000RS\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000TUV\u0000WX\u0000\u0000\u0000\u0000Y".value[ch - 0x1f50]; //$NON-NLS-1$
1608: if (index == 0) {
1609: index = -1;
1610: }
1611: } else if (ch >= 0xfb00) {
1612: if (ch <= 0xfb06) {
1613: index = 90 + ch - 0xfb00;
1614: } else if (ch >= 0xfb13 && ch <= 0xfb17) {
1615: index = 97 + ch - 0xfb13;
1616: }
1617: }
1618: }
1619: }
1620: return index;
1621: }
1622:
1623: /**
1624: * Converts the characters in this String to uppercase, using the specified
1625: * Locale.
1626: *
1627: * @param locale
1628: * the Locale
1629: * @return a new String containing the uppercase characters equivalent to
1630: * the characters in this String
1631: */
1632: public String toUpperCase(Locale locale) {
1633: boolean turkish = "tr".equals(locale.getLanguage()); //$NON-NLS-1$
1634: char[] output = null;
1635: int i = 0;
1636: for (int o = offset, end = offset + count; o < end; o++) {
1637: char ch = value[o];
1638: int index = upperIndex(ch);
1639: if (index == -1) {
1640: if (output != null && i >= output.length) {
1641: char[] newoutput = new char[output.length
1642: + (count / 6) + 2];
1643: System.arraycopy(output, 0, newoutput, 0,
1644: output.length);
1645: output = newoutput;
1646: }
1647: char upch = !turkish ? Character.toUpperCase(ch)
1648: : (ch != 0x69 ? Character.toUpperCase(ch)
1649: : (char) 0x130);
1650: if (ch != upch) {
1651: if (output == null) {
1652: output = new char[count];
1653: i = o - offset;
1654: System.arraycopy(value, offset, output, 0, i);
1655:
1656: }
1657: output[i++] = upch;
1658: } else if (output != null) {
1659: output[i++] = ch;
1660: }
1661: } else {
1662: int target = index * 3;
1663: char val3 = upperValues[target + 2];
1664: if (output == null) {
1665: output = new char[count + (count / 6) + 2];
1666: i = o - offset;
1667: System.arraycopy(value, offset, output, 0, i);
1668: } else if (i + (val3 == 0 ? 1 : 2) >= output.length) {
1669: char[] newoutput = new char[output.length
1670: + (count / 6) + 3];
1671: System.arraycopy(output, 0, newoutput, 0,
1672: output.length);
1673: output = newoutput;
1674: }
1675:
1676: char val = upperValues[target];
1677: output[i++] = val;
1678: val = upperValues[target + 1];
1679: output[i++] = val;
1680: if (val3 != 0) {
1681: output[i++] = val3;
1682: }
1683: }
1684: }
1685: if (output == null) {
1686: return this ;
1687: }
1688: return output.length == i || output.length - i < 8 ? new String(
1689: 0, i, output)
1690: : new String(output, 0, i);
1691: }
1692:
1693: /**
1694: * Answers a copy of this String with white space characters at the
1695: * beginning and end removed.
1696: *
1697: * If the receiver has no leading or trailing blanks then it returns itself.
1698: *
1699: * Blanks are defined as characters with Unicode value
1700: * <code><= \u0020</code>.
1701: *
1702: * @return a new String with leading and trailing blanks removed, or this
1703: * string if there are none.
1704: */
1705: public String trim() {
1706: int start = offset, last = offset + count - 1;
1707: int end = last;
1708: while ((start <= end) && (value[start] <= ' ')) {
1709: start++;
1710: }
1711: while ((end >= start) && (value[end] <= ' ')) {
1712: end--;
1713: }
1714: if (start == offset && end == last) {
1715: return this ;
1716: }
1717: return new String(start, end - start + 1, value);
1718: }
1719:
1720: /**
1721: * Creates a new String containing the characters in the specified character
1722: * array. Modifying the character array after creating the String has no
1723: * effect on the String.
1724: *
1725: * @param data
1726: * the array of characters
1727: * @return the new String
1728: *
1729: * @throws NullPointerException
1730: * when data is null
1731: */
1732: public static String valueOf(char[] data) {
1733: return new String(data, 0, data.length);
1734: }
1735:
1736: /**
1737: * Creates a new String containing the specified characters in the character
1738: * array. Modifying the character array after creating the String has no
1739: * effect on the String.
1740: *
1741: * @param data
1742: * the array of characters
1743: * @param start
1744: * the starting offset in the character array
1745: * @param length
1746: * the number of characters to use
1747: * @return the new String
1748: *
1749: * @throws IndexOutOfBoundsException
1750: * when <code>length < 0, start < 0</code> or
1751: * <code>start + length > data.length</code>
1752: * @throws NullPointerException
1753: * when data is null
1754: */
1755: public static String valueOf(char[] data, int start, int length) {
1756: return new String(data, start, length);
1757: }
1758:
1759: /**
1760: * Converts the specified character to its string representation.
1761: *
1762: * @param value
1763: * the character
1764: * @return the character converted to a string
1765: */
1766: public static String valueOf(char value) {
1767: String s;
1768: if (value < 128) {
1769: s = new String(value, 1, ascii);
1770: } else {
1771: s = new String(0, 1, new char[] { value });
1772: }
1773: s.hashCode = value;
1774: return s;
1775: }
1776:
1777: /**
1778: * Converts the specified double to its string representation.
1779: *
1780: * @param value
1781: * the double
1782: * @return the double converted to a string
1783: */
1784: public static String valueOf(double value) {
1785: return Double.toString(value);
1786: }
1787:
1788: /**
1789: * Converts the specified float to its string representation.
1790: *
1791: * @param value
1792: * the float
1793: * @return the float converted to a string
1794: */
1795: public static String valueOf(float value) {
1796: return Float.toString(value);
1797: }
1798:
1799: /**
1800: * Converts the specified integer to its string representation.
1801: *
1802: * @param value
1803: * the integer
1804: * @return the integer converted to a string
1805: */
1806: public static String valueOf(int value) {
1807: return Integer.toString(value);
1808: }
1809:
1810: /**
1811: * Converts the specified long to its string representation.
1812: *
1813: * @param value
1814: * the long
1815: * @return the long converted to a string
1816: */
1817: public static String valueOf(long value) {
1818: return Long.toString(value);
1819: }
1820:
1821: /**
1822: * Converts the specified object to its string representation. If the object
1823: * is null answer the string <code>"null"</code>, otherwise use
1824: * <code>toString()</code> to get the string representation.
1825: *
1826: * @param value
1827: * the object
1828: * @return the object converted to a string
1829: */
1830: public static String valueOf(Object value) {
1831: return value != null ? value.toString() : "null"; //$NON-NLS-1$
1832: }
1833:
1834: /**
1835: * Converts the specified boolean to its string representation. When the
1836: * boolean is true answer <code>"true"</code>, otherwise answer
1837: * <code>"false"</code>.
1838: *
1839: * @param value
1840: * the boolean
1841: * @return the boolean converted to a string
1842: */
1843: public static String valueOf(boolean value) {
1844: return value ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
1845: }
1846:
1847: /**
1848: * Answers whether the characters in the StringBuffer strbuf are the same as
1849: * those in this String.
1850: *
1851: * @param strbuf
1852: * the StringBuffer to compare this String to
1853: * @return true when the characters in strbuf are identical to those in this
1854: * String. If they are not, false will be returned.
1855: *
1856: * @throws NullPointerException
1857: * when strbuf is null
1858: *
1859: * @since 1.4
1860: */
1861: public boolean contentEquals(StringBuffer strbuf) {
1862: synchronized (strbuf) {
1863: int size = strbuf.length();
1864: if (count != size) {
1865: return false;
1866: }
1867: return regionMatches(0, new String(0, size, strbuf
1868: .getValue()), 0, size);
1869: }
1870: }
1871:
1872: /**
1873: * <p>
1874: * Compares a <code>CharSequence</code> to this <code>String</code> to
1875: * determine if their contents are equal.
1876: * </p>
1877: *
1878: * @param cs
1879: * The character sequence to compare to.
1880: * @return <code>true</code> if equal, otherwise <code>false</code>
1881: * @since 1.5
1882: */
1883: public boolean contentEquals(CharSequence cs) {
1884: if (cs == null) {
1885: throw new NullPointerException();
1886: }
1887:
1888: int len = cs.length();
1889:
1890: if (len != count) {
1891: return false;
1892: }
1893:
1894: if (len == 0 && count == 0) {
1895: return true; // since both are empty strings
1896: }
1897:
1898: return regionMatches(0, cs.toString(), 0, len);
1899: }
1900:
1901: /**
1902: * Determines whether a this String matches a given regular expression.
1903: *
1904: * @param expr
1905: * the regular expression to be matched
1906: * @return true if the expression matches, otherwise false
1907: *
1908: * @throws PatternSyntaxException
1909: * if the syntax of the supplied regular expression is not valid
1910: * @throws NullPointerException
1911: * if expr is null
1912: *
1913: * @since 1.4
1914: */
1915: public boolean matches(String expr) {
1916: return Pattern.matches(expr, this );
1917: }
1918:
1919: /**
1920: * Replace any substrings within this String that match the supplied regular
1921: * expression expr, with the String substitute.
1922: *
1923: * @param expr
1924: * the regular expression to match
1925: * @param substitute
1926: * the string to replace the matching substring with
1927: * @return the new string
1928: *
1929: * @throws NullPointerException
1930: * if expr is null
1931: *
1932: * @since 1.4
1933: */
1934: public String replaceAll(String expr, String substitute) {
1935: return Pattern.compile(expr).matcher(this ).replaceAll(
1936: substitute);
1937: }
1938:
1939: /**
1940: * Replace any substrings within this String that match the supplied regular
1941: * expression expr, with the String substitute.
1942: *
1943: * @param expr
1944: * the regular expression to match
1945: * @param substitute
1946: * the string to replace the matching substring with
1947: * @return the new string
1948: *
1949: * @throws NullPointerException
1950: * if expr is null
1951: *
1952: * @since 1.4
1953: */
1954: public String replaceFirst(String expr, String substitute) {
1955: return Pattern.compile(expr).matcher(this ).replaceFirst(
1956: substitute);
1957: }
1958:
1959: /**
1960: * Replace any substrings within this String that match the supplied regular
1961: * expression expr, with the String substitute.
1962: *
1963: * @param expr
1964: * the regular expression to match
1965: * @return the new string
1966: *
1967: * @throws NullPointerException
1968: * if expr is null
1969: *
1970: * @since 1.4
1971: */
1972: public String[] split(String expr) {
1973: return Pattern.compile(expr).split(this );
1974: }
1975:
1976: /**
1977: * Splits this String using the supplied regular expression expr. max
1978: * controls the number of times that the pattern is applied to the string.
1979: *
1980: * @param expr
1981: * the regular expression used to divide the string
1982: * @param max
1983: * the number of times to apply the pattern
1984: * @return an array of Strings created by separating the string along
1985: * matches of the regular expression.
1986: *
1987: * @throws NullPointerException
1988: * if expr is null
1989: *
1990: * @since 1.4
1991: */
1992: public String[] split(String expr, int max) {
1993: return Pattern.compile(expr).split(this , max);
1994: }
1995:
1996: /**
1997: * Has the same result as the substring function, but is present so that
1998: * String may implement the CharSequence interface.
1999: *
2000: * @param start
2001: * the offset the first character
2002: * @param end
2003: * the offset of one past the last character to include
2004: *
2005: * @return the subsequence requested
2006: *
2007: * @throws IndexOutOfBoundsException
2008: * when start or end is less than zero, start is greater than
2009: * end, or end is greater than the length of the String.
2010: *
2011: * @see java.lang.CharSequence#subSequence(int, int)
2012: *
2013: * @since 1.4
2014: */
2015: public CharSequence subSequence(int start, int end) {
2016: return substring(start, end);
2017: }
2018:
2019: /**
2020: * <p>
2021: * Retrieves the Unicode code point value at the <code>index</code>.
2022: * </p>
2023: *
2024: * @param index
2025: * The index to the <code>char</code> code unit within this
2026: * object.
2027: * @return The Unicode code point value.
2028: * @throws IndexOutOfBoundsException
2029: * if <code>index</code> is negative or greater than or equal
2030: * to {@link #length()}.
2031: * @see Character
2032: * @see Character#codePointAt(char[], int, int)
2033: * @since 1.5
2034: */
2035: public int codePointAt(int index) {
2036: if (index < 0 || index >= count) {
2037: throw new IndexOutOfBoundsException();
2038: }
2039: int s = index + offset;
2040: return Character.codePointAt(value, s, offset + count);
2041: }
2042:
2043: /**
2044: * <p>
2045: * Retrieves the Unicode code point value that precedes the
2046: * <code>index</code>.
2047: * </p>
2048: *
2049: * @param index
2050: * The index to the <code>char</code> code unit within this
2051: * object.
2052: * @return The Unicode code point value.
2053: * @throws IndexOutOfBoundsException
2054: * if <code>index</code> is less than 1 or greater than
2055: * {@link #length()}.
2056: * @see Character
2057: * @see Character#codePointBefore(char[], int, int)
2058: * @since 1.5
2059: */
2060: public int codePointBefore(int index) {
2061: if (index < 1 || index > count) {
2062: throw new IndexOutOfBoundsException();
2063: }
2064: int s = index + offset;
2065: return Character.codePointBefore(value, s);
2066: }
2067:
2068: /**
2069: * <p>
2070: * Calculates the number of Unicode code points between
2071: * <code>beginIndex</code> and <code>endIndex</code>.
2072: * </p>
2073: *
2074: * @param beginIndex
2075: * The inclusive beginning index of the subsequence.
2076: * @param endIndex
2077: * The exclusive end index of the subsequence.
2078: * @return The number of Unicode code points in the subsequence.
2079: * @throws IndexOutOfBoundsException
2080: * if <code>beginIndex</code> is negative or greater than
2081: * <code>endIndex</code> or <code>endIndex</code> is greater
2082: * than {@link #length()}.
2083: * @since 1.5
2084: */
2085: public int codePointCount(int beginIndex, int endIndex) {
2086: if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
2087: throw new IndexOutOfBoundsException();
2088: }
2089: int s = beginIndex + offset;
2090: return Character
2091: .codePointCount(value, s, endIndex - beginIndex);
2092: }
2093:
2094: /**
2095: * <p>
2096: * Determines if this <code>String</code> contains the sequence of
2097: * characters in the <code>CharSequence</code> passed.
2098: * </p>
2099: *
2100: * @param cs
2101: * The character sequence to search for.
2102: * @return <code>true</code> if the sequence of characters are contained
2103: * in this object; otherwise <code>false</code>
2104: * @since 1.5
2105: */
2106: public boolean contains(CharSequence cs) {
2107: if (cs == null) {
2108: throw new NullPointerException();
2109: }
2110: return indexOf(cs.toString()) >= 0;
2111: }
2112:
2113: /**
2114: * <p>
2115: * Returns the index within this object that is offset from
2116: * <code>index</code> by <code>codePointOffset</code> code points.
2117: * </p>
2118: *
2119: * @param index
2120: * The index within this object to calculate the offset from.
2121: * @param codePointOffset
2122: * The number of code points to count.
2123: * @return The index within this object that is the offset.
2124: * @throws IndexOutOfBoundsException
2125: * if <code>index</code> is negative or greater than
2126: * {@link #length()} or if there aren't enough code points
2127: * before or after <code>index</code> to match
2128: * <code>codePointOffset</code>.
2129: * @since 1.5
2130: */
2131: public int offsetByCodePoints(int index, int codePointOffset) {
2132: int s = index + offset;
2133: int r = Character.offsetByCodePoints(value, offset, count, s,
2134: codePointOffset);
2135: return r - offset;
2136: }
2137:
2138: /**
2139: * Returns a printf-style formatted string, using the supplied format and
2140: * arguments. This function is a shortcut to
2141: * <code>format(Locale.getDefault(), format, args)</code>.
2142: *
2143: * @param format
2144: * a format string
2145: * @param args
2146: * arguments to replace format specifiers, may be none
2147: * @throws NullPointerException
2148: * if the format is null
2149: * @throws IllegalArgumentException
2150: * if the format is invalid
2151: * @return The formatted string
2152: * @since 1.5
2153: * @see java.util.Formatter
2154: */
2155: public static String format(String format, Object... args) {
2156: return format(Locale.getDefault(), format, args);
2157: }
2158:
2159: /**
2160: * Returns a printf-style formatted string, using the supplied format and
2161: * arguments, accordingly to the specified locale.
2162: *
2163: * @param loc
2164: * the locale to apply; <code>null</code> value means no
2165: * localization
2166: * @param format
2167: * a format string
2168: * @param args
2169: * arguments to replace format specifiers, may be none
2170: * @throws NullPointerException
2171: * if the format is null
2172: * @throws IllegalArgumentException
2173: * if the format is invalid
2174: * @return The formatted string
2175: * @since 1.5
2176: * @see java.util.Formatter
2177: */
2178: public static String format(Locale loc, String format,
2179: Object... args) {
2180: if (format == null) {
2181: throw new NullPointerException("null format argument");
2182: }
2183: int bufferSize = format.length()
2184: + (args == null ? 0 : args.length * 10);
2185: Formatter f = new Formatter(new StringBuilder(bufferSize), loc);
2186: return f.format(format, args).toString();
2187: }
2188:
2189: /*
2190: * An implementation of a String.indexOf that is supposed to perform
2191: * substantially better than the default algorithm if the "needle" (the
2192: * subString being searched for) is a constant string.
2193: *
2194: * For example, a JIT, upon encoutering a call to String.indexOf(String),
2195: * where the needle is a constant string, may compute the values cache, md2
2196: * and lastChar, and change the call to the following method.
2197: */
2198: @SuppressWarnings("unused")
2199: private static int indexOf(String haystackString,
2200: String needleString, int cache, int md2, char lastChar) {
2201: char[] haystack = haystackString.value;
2202: int haystackOffset = haystackString.offset;
2203: int haystackLength = haystackString.count;
2204: char[] needle = needleString.value;
2205: int needleOffset = needleString.offset;
2206: int needleLength = needleString.count;
2207: int needleLengthMinus1 = needleLength - 1;
2208: int haystackEnd = haystackOffset + haystackLength;
2209: outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) {
2210: if (lastChar == haystack[i]) {
2211: for (int j = 0; j < needleLengthMinus1; ++j) {
2212: if (needle[j + needleOffset] != haystack[i + j
2213: - needleLengthMinus1]) {
2214: int skip = 1;
2215: if ((cache & (1 << haystack[i])) == 0) {
2216: skip += j;
2217: }
2218: i += Math.max(md2, skip);
2219: continue outer_loop;
2220: }
2221: }
2222: return i - needleLengthMinus1 - haystackOffset;
2223: }
2224:
2225: if ((cache & (1 << haystack[i])) == 0) {
2226: i += needleLengthMinus1;
2227: }
2228: i++;
2229: }
2230: return -1;
2231: }
2232:
2233: /*
2234: * Returns the character array for this String.
2235: */
2236: char[] getValue() {
2237: return value;
2238: }
2239: }
|