scolebourne 2004/10/16 08:09:52 Added: lang/src/java/org/apache/commons/lang/text StrBuilder.java Log: Add initial version of StrBuilder, currently without any tests Revision Changes Path 1.1 jakarta-commons/lang/src/java/org/apache/commons/lang/text/StrBuilder.java Index: StrBuilder.java =================================================================== /* * Copyright 2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.lang.text; import java.util.Collection; import java.util.Iterator; /** * Builds a string from consituant parts providing a more flexible and powerful API * than StringBuffer. * <p> * The main differences from StringBuffer/StringBuilder are: * <ul> * <li>Not synchronized</li> * <li>Not final</li> * <li>Subclasses have direct access to character array</li> * <li>Additional methods * <ul> * <li>appendWithSeparators - adds an array of values, with a separator</li> * <li>appendPadding - adds a length padding characters</li> * <li>appendFixedLength - adds a fixed width field to the builder</li> * <li>toCharArray/getChars - simpler ways to get a range of the character array</li> * <li>delete - delete char or string</li> * <li>replace - search and replace for a char or string</li> * <li>leftString/rightString/midString - substring without exceptions</li> * <li>contains - whether the builder contains a char or string</li> * <li>size/clear/isEmpty - collections style API methods</li> * </ul> * </li> * </ul> * <p> * The aim has been to provide an API that mimics very closely what StringBuffer * provides, but with additional methods. It should be noted that some edge cases, * with invalid indices or null input, have been altered - see individual methods. * The biggest of these changes is that by default, null will not output the text * 'null'. This can be controlled by a property, [EMAIL PROTECTED] #setNullText(String)}. * * @author Stephen Colebourne * @since 2.1 * @version $Id: StrBuilder.java,v 1.1 2004/10/16 15:09:52 scolebourne Exp $ */ public class StrBuilder implements Cloneable { /** Serialization lock. */ private static final long serialVersionUID = 7628716375283629643L; /** Internal data storage. */ protected char[] buf; /** Current size of the buffer. */ protected int size; /** The null text. */ private String nullText; //----------------------------------------------------------------------- /** * Constructor that creates an empty builder initial capacity 32 characters. */ public StrBuilder() { this(32); } /** * Constructor that creates an empty builder the specified initial capacity. * * @param initialCapacity the initial capacity, zero or less will be converted to 32 */ public StrBuilder(int initialCapacity) { super(); if (initialCapacity <= 0) { initialCapacity = 32; } buf = new char[initialCapacity]; } /** * Constructor that creates a builder from the string, allocating * 32 extra characters for growth. * * @param str the string to copy, null treated as blank string */ public StrBuilder(String str) { super(); if (str == null) { buf = new char[32]; } else { buf = new char[str.length() + 32]; append(str); } } //----------------------------------------------------------------------- /** * Gets the text to be appended when null is added. * * @return the null text, null means no append */ public String getNullText() { return nullText; } /** * Sets the text to be appended when null is added. * * @param str the null text, null means no append */ public void setNullText(String str) { if (str != null && str.length() == 0) { str = null; } nullText = str; } //----------------------------------------------------------------------- /** * Gets the length of the string builder. * * @return the length */ public int length() { return size; } /** * Updates the length of the builder by either dropping the last characters * or adding filler of unicode zero. * * @param length the length to set to, must be zero or positive * @throws IndexOutOfBoundsException if the length is negative */ public void setLength(int length) { if (length < 0) { throw new StringIndexOutOfBoundsException(length); } if (length == size) { // ok } else if (length < size) { size = length; } else { ensureCapacity(length); int oldEnd = size; int newEnd = length; size = length; for (int i = oldEnd; i < newEnd; i++) { buf[i] = '\0'; } } } //----------------------------------------------------------------------- /** * Gets the current size of the internal character array buffer. * * @return the capacity */ public int capacity() { return buf.length; } /** * Checks the capacity and ensures that it is at least the size specified. * * @param capacity the capacity to ensure */ public void ensureCapacity(int capacity) { if (capacity > buf.length) { char[] old = buf; buf = new char[capacity]; System.arraycopy(old, 0, buf, 0, size); } } /** * Minimizes the capacity to the actual length of the string. */ public void minimizeCapacity() { if (buf.length > length()) { char[] old = buf; buf = new char[length()]; System.arraycopy(old, 0, buf, 0, size); } } //----------------------------------------------------------------------- /** * Gets the length of the string builder. * <p> * This method is the same as [EMAIL PROTECTED] #length()} and is provided to match the * API of Collections. * * @return the length */ public int size() { return size; } /** * Clears the string builder (convenience Collections API style method). * <p> * This method is the same as [EMAIL PROTECTED] #setLength(0)} and is provided to match the * API of Collections. */ public void clear() { size = 0; } /** * Checks is the string builder is empty (convenience Collections API style method). * <p> * This method is the same as checking [EMAIL PROTECTED] #length()} and is provided to match the * API of Collections. */ public boolean isEmpty() { return (size == 0); } //----------------------------------------------------------------------- /** * Gets the character at the specified index. * * @param index the index to retrieve, must be valid * @return the character at the index * @throws IndexOutOfBoundsException if the index is invalid */ public char charAt(int index) { if (index < 0 || index >= length()) { throw new StringIndexOutOfBoundsException(index); } return buf[index]; } /** * Sets the character at the specified index. * * @param index the index to set * @param ch the new character * @throws IndexOutOfBoundsException if the index is invalid */ public void setCharAt(int index, char ch) { if (index < 0 || index >= length()) { throw new StringIndexOutOfBoundsException(index); } buf[index] = ch; } //----------------------------------------------------------------------- /** * Copies the builder's character array into a new character array. * * @return a new array that represents the contents of the builder */ public char[] toCharArray() { char chars[] = new char[size]; System.arraycopy(buf, 0, chars, 0, size); return chars; } /** * Copies part of the builder's character array into a new character array. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @return a new array that holds part of the contents of the builder */ public char[] toCharArray(int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); char chars[] = new char[size]; System.arraycopy(buf, startIndex, chars, 0, endIndex - startIndex); return chars; } /** * Copies the character array into the specified array. * * @param destination the destination array, null will cause an array to be created * @return the input array, unless that was null or too small */ public char[] getChars(char[] destination) { int len = length(); if (destination == null || destination.length < len) { destination = new char[len]; } System.arraycopy(buf, 0, destination, 0, len); return destination; } /** * Copies the character array into the specified array. * * @param startIndex first index to copy, inclusive, must be valid * @param endIndex last index, exclusive, must be valid * @param destination the destination array, must not be null or too small * @param destinationIndex the index to start copying in destination * @throws NullPointerException if the array is null * @throws IndexOutOfBoundsException if any index is invalid */ public void getChars(int startIndex, int endIndex, char destination[], int destinationIndex) { if (startIndex < 0) { throw new StringIndexOutOfBoundsException(startIndex); } if (endIndex < 0 || endIndex > length()) { throw new StringIndexOutOfBoundsException(endIndex); } if (startIndex > endIndex) { throw new StringIndexOutOfBoundsException("end < start"); } System.arraycopy(buf, startIndex, destination, destinationIndex, endIndex - startIndex); } //----------------------------------------------------------------------- /** * Appends the text representing <code>null</code> to the string builder. * * @param obj the object to append * @return this, to enable chaining */ public StrBuilder appendNull() { if (nullText == null) { return this; } return append(nullText); } /** * Appends an object to the string builder. * Appending null will call [EMAIL PROTECTED] #appendNull()}. * * @param obj the object to append * @return this, to enable chaining */ public StrBuilder append(Object obj) { if (obj == null) { return appendNull(); } else { return append(obj.toString()); } } /** * Appends a string to the string builder. * Appending null will call [EMAIL PROTECTED] #appendNull()}. * * @param str the string to append * @return this, to enable chaining */ public StrBuilder append(String str) { if (str == null) { return appendNull(); } int strLen = str.length(); if (strLen > 0) { int len = length(); ensureCapacity(len + strLen); str.getChars(0, strLen, buf, len); size += strLen; } return this; } /** * Appends a string buffer to the string builder. * Appending null will call [EMAIL PROTECTED] #appendNull()}. * * @param str the string buffer to append * @return this, to enable chaining */ public StrBuilder append(StringBuffer str) { if (str == null) { return appendNull(); } int strLen = str.length(); if (strLen > 0) { int len = length(); ensureCapacity(len + strLen); str.getChars(0, strLen, buf, len); size += strLen; } return this; } /** * Appends another string builder to the string builder. * Appending null will call [EMAIL PROTECTED] #appendNull()}. * * @param str the string builder to append * @return this, to enable chaining */ public StrBuilder append(StrBuilder str) { if (str == null) { return appendNull(); } int strLen = str.length(); if (strLen > 0) { int len = length(); ensureCapacity(len + strLen); System.arraycopy(str.buf, 0, buf, len, strLen); size += strLen; } return this; } /** * Appends a char array to the string builder. * Appending null has no effect. * <p> * Note: This method treats a null char array as an empty char array, * unlike StringBuffer or String. * * @param chars the char array to append * @return this, to enable chaining */ public StrBuilder append(char[] chars) { if (chars == null) { return this; } int strLen = chars.length; if (strLen > 0) { int len = length(); ensureCapacity(len + strLen); System.arraycopy(chars, 0, buf, len, strLen); size += strLen; } return this; } /** * Appends a char array to the string builder. * Appending null has no effect. * <p> * Note: This method treats a null char array as an empty char array, * unlike StringBuffer or String. * * @param chars the char array to append * @param startIndex the start index, inclusive, must be valid * @param length the length to append, must be valid * @return this, to enable chaining */ public StrBuilder append(char[] chars, int startIndex, int length) { if (chars == null) { return this; } if (length < 0) { throw new StringIndexOutOfBoundsException("length must not be negative"); } if (length > 0) { int len = length(); ensureCapacity(len + length); System.arraycopy(chars, startIndex, buf, len, length); size += length; } return this; } /** * Appends a boolean value to the string builder. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(boolean value) { if (value) { ensureCapacity(size + 4); buf[size++] = 't'; buf[size++] = 'r'; buf[size++] = 'u'; buf[size++] = 'e'; } else { ensureCapacity(size + 5); buf[size++] = 'f'; buf[size++] = 'a'; buf[size++] = 'l'; buf[size++] = 's'; buf[size++] = 'e'; } return this; } /** * Appends a char value to the string builder. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(char ch) { int len = length(); ensureCapacity(len + 1); buf[size++] = ch; return this; } /** * Appends an int value to the string builder using <code>String.valueOf</code>. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(int value) { return append(String.valueOf(value)); } /** * Appends a long value to the string builder using <code>String.valueOf</code>. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(long value) { return append(String.valueOf(value)); } /** * Appends a float value to the string builder using <code>String.valueOf</code>. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(float value) { return append(String.valueOf(value)); } /** * Appends a double value to the string builder using <code>String.valueOf</code>. * * @param value the value to append * @return this, to enable chaining */ public StrBuilder append(double value) { return append(String.valueOf(value)); } //----------------------------------------------------------------------- /** * Appends an array placing separators between each pair of values, but * not after the last. * Appending a null array will have no effect. * Each object is appended using [EMAIL PROTECTED] #append(Object)}. * * @param array the array to append * @param separator the separator to use, null means no separator * @return this, to enable chaining */ public StrBuilder appendWithSeparators(Object[] array, String separator) { if (array != null && array.length > 0) { separator = (separator == null ? "" : separator); append(array[0]); for (int i = 1; i < array.length; i++) { append(separator); append(array[i]); } } return this; } /** * Appends a collection placing separators between each pair of values, but * not after the last. * Appending a null collection will have no effect. * Each object is appended using [EMAIL PROTECTED] #append(Object)}. * * @param coll the collection to append * @param separator the separator to use, null means no separator * @return this, to enable chaining */ public StrBuilder appendWithSeparators(Collection coll, String separator) { if (coll != null && coll.size() > 0) { separator = (separator == null ? "" : separator); Iterator it = coll.iterator(); append(it.next()); while (it.hasNext()) { append(separator); append(it.next()); } } return this; } //----------------------------------------------------------------------- /** * Appends the pad character to the builder the specified number of times. * * @param length the length to append, negative means no append * @param padChar the character to append * @return this, to enable chaining */ public StrBuilder appendPadding(int length, char padChar) { if (length >= 0) { ensureCapacity(size + length); for (int i = 0; i < length; i++) { buf[size++] = padChar; } } return this; } /** * Appends an object to the builder padding on the left to a fixed length. * If the object is larger than the length, the left hand side is lost. * If the object is null, the null text value is used. * * @param obj the object to append * @param length the fixed field width * @param padChar the pad character to use * @return this, to enable chaining */ public StrBuilder appendFixedLengthPadLeft(Object obj, int length, char padChar) { if (length > 0) { ensureCapacity(size + length); String str = (obj == null ? getNullText() : obj.toString()); int strLen = str.length(); if (strLen >= length) { str.getChars(strLen - length, strLen, buf, size); } else { int padLen = length - strLen; for (int i = 0; i < padLen; i++) { buf[size + i] = padChar; } str.getChars(0, strLen, buf, size + padLen); } size += length; } return this; } /** * Appends an object to the builder padding on the right to a fixed length. * If the object is larger than the length, the right hand side is lost. * If the object is null, null text value is used. * * @param obj the object to append * @param length the fixed field width * @param padChar the pad character to use * @return this, to enable chaining */ public StrBuilder appendFixedLengthPadRight(Object obj, int length, char padChar) { if (length > 0) { ensureCapacity(size + length); String str = (obj == null ? getNullText() : obj.toString()); int strLen = str.length(); if (strLen >= length) { str.getChars(strLen - length, strLen, buf, size); } else { int padLen = length - strLen; str.getChars(0, strLen, buf, size); for (int i = 0; i < padLen; i++) { buf[size + strLen + i] = padChar; } } size += length; } return this; } //----------------------------------------------------------------------- /** * Inserts the string representation of an object into this builder. * Inserting null will use the stored null text value. * * @param index the index to add at, must be valid * @param obj the object to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, Object obj) { if (obj == null) { return insert(index, nullText); } else { return insert(index, obj.toString()); } } /** * Inserts the string into this builder. * Inserting null will use the stored null text value. * * @param index the index to add at, must be valid * @param str the string to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, String str) { validateIndex(index); if (str == null) { str = nullText; } int strLen = (str == null ? 0 : str.length()); if (strLen > 0) { int newSize = size + strLen; ensureCapacity(newSize); System.arraycopy(buf, index, buf, index + strLen, size - index); size = newSize; str.getChars(0, strLen, buf, index); } return this; } /** * Inserts the character array into this builder. * Inserting null has no effect. * <p> * Note: This method treats a null char array as an empty char array, * unlike StringBuffer or String. * * @param index the index to add at, must be valid * @param chars the char array to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, char chars[]) { validateIndex(index); if (chars == null) { return this; } int len = chars.length; if (len > 0) { ensureCapacity(size + len); System.arraycopy(buf, index, buf, index + len, size - index); System.arraycopy(chars, 0, buf, index, len); size += len; } return this; } /** * Inserts part of the character array into this builder. * Inserting null has no effect. * <p> * Note: This method treats a null char array as an empty char array, * unlike StringBuffer or String. * * @param index the index to add at, must be valid * @param chars the char array to insert * @param offset the offset into the character array to start at, must be valid * @param length the length of the character array part to copy, must be positive * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if any index is invalid */ public StrBuilder insert(int index, char chars[], int offset, int length) { validateIndex(index); if (chars == null) { return this; } if (offset < 0 || offset > chars.length) { throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); } if (length < 0 || offset + length > chars.length) { throw new StringIndexOutOfBoundsException("Invalid length: " + length); } if (length > 0) { ensureCapacity(size + length); System.arraycopy(buf, index, buf, index + length, size - index); System.arraycopy(chars, offset, buf, index, length); size += length; } return this; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, boolean value) { validateIndex(index); if (value) { ensureCapacity(size + 4); System.arraycopy(buf, index, buf, index + 4, size - index); buf[index++] = 't'; buf[index++] = 'r'; buf[index++] = 'u'; buf[index] = 'e'; size += 4; } else { ensureCapacity(size + 5); System.arraycopy(buf, index, buf, index + 5, size - index); buf[index++] = 'f'; buf[index++] = 'a'; buf[index++] = 'l'; buf[index++] = 's'; buf[index] = 'e'; size += 5; } return this; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, char value) { validateIndex(index); ensureCapacity(size + 1); System.arraycopy(buf, index, buf, index + 1, size - index); buf[index] = value; size++; return this; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, int value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, long value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, float value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid * @param value the value to insert * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder insert(int index, double value) { return insert(index, String.valueOf(value)); } //----------------------------------------------------------------------- /** * Deletes the characters between the two specified indices. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder delete(int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); int len = endIndex - startIndex; if (len > 0) { System.arraycopy(buf, endIndex, buf, startIndex, size - endIndex); size -= len; } return this; } /** * Deletes the character at the specified index. * * @param index the index to delete * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder deleteCharAt(int index) { if (index < 0 || index >= size) { throw new StringIndexOutOfBoundsException(index); } System.arraycopy(buf, index + 1, buf, index, size - index - 1); size--; return this; } /** * Deletes the character wherever it occurs in the builder. * * @param ch the character to delete * @return this, to enable chaining */ public StrBuilder delete(char ch) { for (int i = 0; i < size; i++) { if (buf[i] == ch) { int start = i; while (++i < size) { if (buf[i] != ch) { break; } } System.arraycopy(buf, i, buf, start, size - i); size -= (i - start); } } return this; } /** * Deletes the string wherever it occurs in the builder. * * @param str the string to delete, null causes no action * @return this, to enable chaining */ public StrBuilder delete(String str) { int len = (str == null ? 0 : str.length()); if (len > 0) { int index = indexOf(str, 0); while (index >= 0) { delete(index, index + len); index = indexOf(str, index); } } return this; } //----------------------------------------------------------------------- /** * Replaces a portion of the string builder with another string. * The length of the inserted string does not have to match the removed length. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @param str the string to replace with * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder replace(int startIndex, int endIndex, String str) { endIndex = validateRange(startIndex, endIndex); int insertLen = str.length(); int removeLen = endIndex = startIndex; int newSize = size - removeLen + insertLen; if (insertLen > removeLen) { ensureCapacity(newSize); } if (insertLen != removeLen) { System.arraycopy(buf, endIndex, buf, startIndex + insertLen, size - endIndex); size = newSize; } str.getChars(0, insertLen, buf, startIndex); return this; } /** * Replaces a portion of the string builder with another string builder. * The length of the inserted string does not have to match the removed length. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @param builder the string builder to replace with * @return this, to enable chaining * @throws StringIndexOutOfBoundsException if the index is invalid */ public StrBuilder replace(int startIndex, int endIndex, StrBuilder builder) { endIndex = validateRange(startIndex, endIndex); int insertLen = builder.length(); int removeLen = endIndex = startIndex; if (insertLen > removeLen) { ensureCapacity(size - removeLen + insertLen); } if (insertLen != removeLen) { System.arraycopy(buf, endIndex, buf, startIndex + insertLen, size - endIndex); } builder.getChars(0, insertLen, buf, startIndex); return this; } /** * Replaces the search character with the replace character throughout the builder. * * @param search the search string, null causes no action to occur * @param replace the replace string, null is equivalent to an empty string * @return this, to enable chaining */ public StrBuilder replace(char search, char replace) { if (search != replace) { for (int i = 0; i < size; i++) { if (buf[i] == search) { buf[i] = replace; } } } return this; } /** * Replaces the search string with the replace string throughout the builder. * * @param searchStr the search string, null causes no action to occur * @param replaceStr the replace string, null is equivalent to an empty string * @return this, to enable chaining */ public StrBuilder replace(String searchStr, String replaceStr) { int searchLen = (searchStr == null ? 0 : searchStr.length()); if (searchLen > 0) { replaceStr = (replaceStr == null ? "" : replaceStr); int index = indexOf(searchStr, 0); while (index >= 0) { replace(index, index + searchLen, replaceStr); index = indexOf(searchStr, index); } } return this; } //----------------------------------------------------------------------- /** * Checks whether this builder starts with the specified string. * <p> * Note that this method handles null input quietly, unlike String. * * @param str the string to search for, null returns false * @return true if the builder starts with the string */ public boolean startsWith(String str) { if (str == null) { return false; } int len = str.length(); if (len == 0) { return true; } if (len > size) { return false; } for (int i = 0; i < len; i++) { if (buf[i] != str.charAt(i)) { return false; } } return true; } /** * Checks whether this builder ends with the specified string. * <p> * Note that this method handles null input quietly, unlike String. * * @param str the string to search for, null returns false * @return true if the builder ends with the string */ public boolean endsWith(String str) { if (str == null) { return false; } int len = str.length(); if (len == 0) { return true; } if (len > size) { return false; } int pos = size - len; for (int i = 0; i < len; i++,pos++) { if (buf[pos] != str.charAt(i)) { return false; } } return true; } //----------------------------------------------------------------------- /** * Extracts a portion of this string builder as a string. * * @param startIndex the start index, inclusive, must be valid * @return the new string * @throws StringIndexOutOfBoundsException if the index is invalid */ public String substring(int start) { return substring(start, size); } /** * Extracts a portion of this string builder as a string. * <p> * Note: This method treats an endIndex greater than the length of the * builder as equal to the length of the builder, and continues * without error, unlike StringBuffer or String. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @return the new string * @throws StringIndexOutOfBoundsException if the index is invalid */ public String substring(int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); return new String(buf, startIndex, endIndex - startIndex); } /** * Extracts the leftmost characters from the string builder without * throwing an exception. * <p> * This method extracts the left <code>length</code> characters from * the builder. If this many characters are not available, the whole * builder is returned. Thus the returned string may be shorter than the * length requested. * * @param length the number of characters to extract, negative returns empty string * @return the new string */ public String leftString(int length) { if (length <= 0) { return ""; } else if (length >= size) { return new String(buf, 0, size); } else { return new String(buf, 0, length); } } /** * Extracts the rightmost characters from the string builder without * throwing an exception. * <p> * This method extracts the right <code>length</code> characters from * the builder. If this many characters are not available, the whole * builder is returned. Thus the returned string may be shorter than the * length requested. * * @param length the number of characters to extract, negative returns empty string * @return the new string */ public String rightString(int length) { if (length <= 0) { return ""; } else if (length >= size) { return new String(buf, 0, size); } else { return new String(buf, size - length, size); } } /** * Extracts some characters from the middle of the string builder without * throwing an exception. * <p> * This method extracts <code>length</code> characters from the builder * at the specified index. * If the index is negative it is treated as zero. * If the index is greater than the builder size, it is treated as the builder size. * If the length is negative, the empty string is returned. * If insufficient characters are available in the builder, as much as possible is returned. * Thus the returned string may be shorter than the length requested. * * @param index the index to start at, negative means zero * @param length the number of characters to extract, negative returns empty string * @return the new string */ public String midString(int index, int length) { if (index < 0) { index = 0; } if (length <= 0 || index >= size) { return ""; } if (size <= index + length) { return new String(buf, index, size - index); } else { return new String(buf, index, length); } } //----------------------------------------------------------------------- /** * Checks of the string builder contains the specified char. * * @param ch the character to find * @return true if the builder contains the character */ public boolean contains(char ch) { char[] thisBuf = buf; for (int i = 0; i < thisBuf.length; i++) { if (thisBuf[i] == ch) { return true; } } return false; } /** * Checks of the string builder contains the specified string. * * @param str the string to find * @return true if the builder contains the string */ public boolean contains(String str) { return (indexOf(str, 0) >= 0); } //----------------------------------------------------------------------- /** * Searches the string builder to find the first reference to the specified char. * * @param ch the character to find * @return the first index of the character, or -1 if not found */ public int indexOf(char ch) { return indexOf(ch, 0); } /** * Searches the string builder to find the first reference to the specified char. * * @param ch the character to find * @param startIndex the index to start at, must be valid * @return the first index of the character, or -1 if not found */ public int indexOf(char ch, int startIndex) { startIndex = (startIndex < 0 ? 0 : startIndex); if (startIndex >= size) { return -1; } char[] thisBuf = buf; for (int i = startIndex; i < thisBuf.length; i++) { if (thisBuf[i] == ch) { return i; } } return -1; } /** * Searches the string builder to find the first reference to the specified string. * <p> * Note that a null input string will return -1, whereas the JDK throws an exception. * * @param str the string to find, null returns -1 * @return the first index of the string, or -1 if not found */ public int indexOf(String str) { return indexOf(str, 0); } /** * Searches the string builder to find the first reference to the specified * string starting searching from the given index. * <p> * Note that a null input string will return -1, whereas the JDK throws an exception. * * @param str the string to find, null returns -1 * @param startIndex the index to start at, must be valid * @return the first index of the string, or -1 if not found */ public int indexOf(String str, int startIndex) { startIndex = (startIndex < 0 ? 0 : startIndex); if (startIndex >= size) { return -1; } int strLen = (str == null ? 0 : str.length()); if (strLen > 0 && strLen <= size) { if (strLen == 1) { return indexOf(str.charAt(0), startIndex); } char[] thisBuf = buf; outer: for (int i = startIndex; i < thisBuf.length - strLen; i++) { for (int j = 0; j < strLen; j++) { if (str.charAt(j) != thisBuf[i + j]) { continue outer; } } return i; } } else if (strLen == 0) { return 0; } return -1; } //----------------------------------------------------------------------- /** * Searches the string builder to find the last reference to the specified char. * * @param ch the character to find * @return the last index of the character, or -1 if not found */ public int lastIndexOf(char ch) { return lastIndexOf(ch, 0); } /** * Searches the string builder to find the last reference to the specified char. * * @param ch the character to find * @param startIndex the index to start at, invalid index rounded to edge * @return the last index of the character, or -1 if not found */ public int lastIndexOf(char ch, int startIndex) { startIndex = (startIndex >= size ? size - 1 : startIndex); if (startIndex < 0) { return -1; } char[] thisBuf = buf; for (int i = startIndex; i >= 0; i--) { if (thisBuf[i] == ch) { return i; } } return -1; } /** * Searches the string builder to find the last reference to the specified string. * <p> * Note that a null input string will return -1, whereas the JDK throws an exception. * * @param str the string to find, null returns -1 * @return the last index of the string, or -1 if not found */ public int lastIndexOf(String str) { return lastIndexOf(str, size); } /** * Searches the string builder to find the last reference to the specified * string starting searching from the given index. * <p> * Note that a null input string will return -1, whereas the JDK throws an exception. * * @param str the string to find, null returns -1 * @param startIndex the index to start at, invalid index rounded to edge * @return the last index of the string, or -1 if not found */ public int lastIndexOf(String str, int startIndex) { startIndex = (startIndex >= size ? size - 1 : startIndex); if (startIndex < 0) { return -1; } int strLen = (str == null ? 0 : str.length()); if (strLen > 0 && strLen <= size) { if (strLen == 1) { return lastIndexOf(str.charAt(0), startIndex); } char[] thisBuf = buf; outer: for (int i = startIndex - strLen; i >= 0; i--) { for (int j = 0; j < strLen; j++) { if (str.charAt(j) != thisBuf[i + j]) { continue outer; } } return i; } } else if (strLen == 0) { return startIndex; } return -1; } /** * Reverses the string builder placing each character in the opposite index. * * @return this, to enable chaining */ public StrBuilder reverse() { int half = size / 2; char swap; for (int i = 0; i < half; i++) { swap = buf[i]; buf[i] = buf[size - i]; buf[size - i] = swap; } return this; } /** * Gets a String version of the string builder, creating a new instance * each time the method is called. * <p> * Note that unlike StringBuffer, the string version returned is * independent of the string builder. * * @return the builder as a String */ public String toString() { return new String(buf, 0, size); } //----------------------------------------------------------------------- /** * Validates parameters defining a range of the builder. * * @param startIndex the start index, inclusive, must be valid * @param endIndex the end index, exclusive, must be valid except * that if too large it is treated as end of string * @return the new string * @throws StringIndexOutOfBoundsException if the index is invalid */ protected int validateRange(int startIndex, int endIndex) { if (startIndex < 0) { throw new StringIndexOutOfBoundsException(startIndex); } if (endIndex > size) { endIndex = size; } if (startIndex > endIndex) { throw new StringIndexOutOfBoundsException("end < start"); } return endIndex; } /** * Validates parameters defining a single index in the builder. * * @param index the index, must be valid * @throws StringIndexOutOfBoundsException if the index is invalid */ protected void validateIndex(int index) { if (index < 0 || index > size) { throw new StringIndexOutOfBoundsException(index); } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
