Tenfold improvement in performance for leftPad, rightPad and repeat when repeat is over a String of length 1, by implementation of a padding method. The padding method is kept private for the moment.

Also a modification of containsOnly so it has a partner method indexOfAnyBut. Unit Test added for indexOfAnyBut.

Submitted by:	Robert Simpson


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137299 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Henri Yandell 2003-04-16 04:37:33 +00:00
parent 92a9a68b72
commit eb6a2942c0
2 changed files with 222 additions and 12 deletions

View File

@ -76,10 +76,30 @@ import java.util.StringTokenizer;
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @author Arun Mammen Thomas
* @since 1.0
* @version $Id: StringUtils.java,v 1.43 2003/04/10 00:01:21 ggregory Exp $
* @version $Id: StringUtils.java,v 1.44 2003/04/16 04:37:33 bayard Exp $
*/
public class StringUtils {
/**
* <p>The maximum size to which the padding constant(s) can expand.</p>
*/
private static int PAD_LIMIT = 8192;
/**
* <p>A <code>String</code> containing all blank characters.</p>
*
* <p>Used for efficient blank padding. The length of the string expands as needed.</p>
*/
private static String blanks = new String(" ");
/**
* <p>An array of <code>String</code>s used for padding.</p>
*
* <p>Used for efficient blank padding. The length of each string expands as needed.</p>
*/
private final static String[] padding = new String[Character.MAX_VALUE];
// String.concat about twice as fast as StringBuffer.append
/**
* <p><code>StringUtils<code> instances should NOT be constructed in
* standard programming. Instead, the class should be used as
@ -1178,6 +1198,10 @@ public class StringUtils {
* @throws NullPointerException if str is <code>null</code>
*/
public static String repeat(String str, int repeat) {
if (str.length() == 1 && repeat <= PAD_LIMIT) {
return padding(repeat, str.charAt(0));
}
StringBuffer buffer = new StringBuffer(repeat * str.length());
for (int i = 0; i < repeat; i++) {
buffer.append(str);
@ -1185,20 +1209,84 @@ public class StringUtils {
return buffer.toString();
}
/**
* <p>Returns blank padding with a given length.</p>
*
* @param repeat number of times to repeat a blank
* @return String with repeated character
* @throws IndexOutOfBoundsException if repeat < 0
*/
private static String padding(int repeat) {
while (blanks.length() < repeat) {
blanks = blanks.concat(blanks);
}
return blanks.substring(0, repeat);
}
/**
* <p>Returns padding using the specified delimiter repeated to a given length.
* </p>
*
* @param repeat number of times to repeat delim
* @param delim character to repeat
* @return String with repeated character
* @throws NullPointerException if delim is <code>null</code>
* @throws IndexOutOfBoundsException if repeat < 0
*/
private static String padding(int repeat, char delim) {
if (padding[delim] == null) {
padding[delim] = String.valueOf(delim);
}
while (padding[delim].length() < repeat) {
padding[delim] = padding[delim].concat(padding[delim]);
}
return padding[delim].substring(0, repeat);
}
/**
* <p>Right pad a String with spaces.</p>
*
* <p>The String is padded to the size of <code>n</code>.</p>
*
* @param str String to repeat
* @param str String to pad out
* @param size number of times to repeat str
* @return right padded String
* @return right padded String or original String if no padding is necessary
* @throws NullPointerException if str is <code>null</code>
*/
public static String rightPad(String str, int size) {
return rightPad(str, size, " ");
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original string when possible
}
if (pads > PAD_LIMIT) {
return rightPad(str, size, " ");
}
return str + padding(pads);
}
/**
* <p>Right pad a String with a specified character.</p>
*
* <p>The String is padded to the size of <code>n</code>.</p>
*
* @param str String to pad out
* @param size size to pad to
* @param delim character to pad with
* @return right padded String or original String if no padding is necessary
* @throws NullPointerException if str or delim is <code>null<code>
*/
public static String rightPad(String str, int size, char delim) {
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original string when possible
}
if (pads > PAD_LIMIT) {
return rightPad(str, size, String.valueOf(delim));
}
return str + padding(pads, delim);
}
/**
* <p>Right pad a String with a specified string.</p>
*
@ -1207,11 +1295,15 @@ public class StringUtils {
* @param str String to pad out
* @param size size to pad to
* @param delim String to pad with
* @return right padded String
* @return right padded String or original String if no padding is necessary
* @throws NullPointerException if str or delim is <code>null<code>
* @throws ArithmeticException if delim is the empty String
*/
public static String rightPad(String str, int size, String delim) {
if (delim.length() == 1 && size - str.length() <= PAD_LIMIT) {
return rightPad(str, size, delim.charAt(0));
}
size = (size - str.length()) / delim.length();
if (size > 0) {
str += repeat(delim, size);
@ -1226,23 +1318,53 @@ public class StringUtils {
*
* @param str String to pad out
* @param size size to pad to
* @return left padded String
* @return left padded String or original String if no padding is necessary
* @throws NullPointerException if str or delim is <code>null<code>
*/
public static String leftPad(String str, int size) {
return leftPad(str, size, " ");
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original string when possible
}
if (pads > PAD_LIMIT) {
return leftPad(str, size, " ");
}
return padding(pads).concat(str);
}
/**
* Left pad a String with a specified character. Pad to a size of n.
*
* @param str String to pad out
* @param size size to pad to
* @param delim character to pad with
* @return left padded String or original String if no padding is necessary
* @throws NullPointerException if str or delim is <code>null</code>
*/
public static String leftPad(String str, int size, char delim) {
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original string when possible
}
if (pads > PAD_LIMIT) {
return leftPad(str, size, " ");
}
return padding(pads, delim).concat(str);
}
/**
* Left pad a String with a specified string. Pad to a size of n.
*
* @param str String to pad out
* @param size size to pad to
* @param delim String to pad with
* @return left padded String
* @return left padded String or original String if no padding is necessary
* @throws NullPointerException if str or delim is null
* @throws ArithmeticException if delim is the empty string
*/
public static String leftPad(String str, int size, String delim) {
if (delim.length() == 1 && size - str.length() <= PAD_LIMIT)
return leftPad(str, size, delim.charAt(0));
size = (size - str.length()) / delim.length();
if (size > 0) {
str = repeat(delim, size) + str;
@ -1813,6 +1935,7 @@ public class StringUtils {
* @param validChars an array of valid chars
* @return true if it only contains valid chars and is non-null
*/
/* rewritten
public static boolean containsOnly(String str, char[] validChars) {
if (str == null || validChars == null) {
return false;
@ -1834,6 +1957,7 @@ public class StringUtils {
}
return true;
}
*/
/**
* <p>Checks that the String does not contain certain chars.</p>
@ -1873,6 +1997,66 @@ public class StringUtils {
return true;
}
/**
* <p>Checks if the String contains only certain chars.</p>
*
* @param str the String to check
* @param valid an array of valid chars
* @return true if it only contains valid chars and is non-null
*/
public static boolean containsOnly(String str, char[] valid) {
// All these pre-checks are to maintain API with an older version
if( (valid == null) || (str == null) ) {
return false;
}
if(str.length() == 0) {
return true;
}
if(valid.length == 0) {
return false;
}
return indexOfAnyBut(str, valid) == -1;
}
/**
* <p>Search a String to find the first index of any
* character not in the given set of characters.</p>
*
* @param str the String to check
* @param searchChars the chars to search for
* @return the index of any of the chars
* @throws NullPointerException if either str or searchChars is <code>null</code>
*/
public static int indexOfAnyBut(String str, char[] searchChars) {
if(searchChars == null) {
return -1;
}
return indexOfAnyBut(str, new String(searchChars));
}
/**
* <p>Search a String to find the first index of any
* character not in the given set of characters.</p>
*
* @param str the String to check
* @param searchChars a String containing the chars to search for
* @return the last index of any of the chars
* @throws NullPointerException if either str or searchChars is <code>null</code>
*/
public static int indexOfAnyBut(String str, String searchChars) {
if (str == null || searchChars == null) {
return -1;
}
for (int i = 0; i < str.length(); i ++) {
if (searchChars.indexOf(str.charAt(i)) < 0) {
return i;
}
}
return -1;
}
// Defaults
//--------------------------------------------------------------------------
@ -1955,7 +2139,7 @@ public class StringUtils {
* In no case will it return a string of length greater than maxWidth.
*
* @param maxWidth maximum length of result string
**/
*/
public static String abbreviate(String s, int maxWidth) {
return abbreviate(s, 0, maxWidth);
}
@ -1971,7 +2155,7 @@ public class StringUtils {
*
* @param offset left edge of source string
* @param maxWidth maximum length of result string
**/
*/
public static String abbreviate(String s, int offset, int maxWidth) {
if (maxWidth < 4)
throw new IllegalArgumentException("Minimum abbreviation width is 4");
@ -2103,3 +2287,4 @@ public class StringUtils {
}
}

View File

@ -69,7 +69,7 @@ import junit.textui.TestRunner;
* @author <a href="mailto:fredrik@westermarck.com>Fredrik Westermarck</a>
* @author Holger Krauth
* @author <a href="hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id: StringUtilsTest.java,v 1.18 2003/04/09 18:45:29 alex Exp $
* @version $Id: StringUtilsTest.java,v 1.19 2003/04/16 04:37:33 bayard Exp $
*/
public class StringUtilsTest extends TestCase {
@ -564,6 +564,31 @@ public class StringUtilsTest extends TestCase {
assertEquals("containsNone(str3, chars3)", true, StringUtils.containsNone(str3, chars3));
}
public void testIndexOfAnyBut() {
String str1 = "a";
String str2 = "b";
String str3 = "ab";
String chars1= "b";
String chars2= "a";
String chars3= "ab";
String emptyChars = "";
assertEquals("indexOfAnyBut(null, null)", -1, StringUtils.indexOfAnyBut(null, (String) null));
assertEquals("indexOfAnyBut(empty-string, null)", -1, StringUtils.indexOfAnyBut("", (String) null));
assertEquals("indexOfAnyBut(null, empty-string)", -1, StringUtils.indexOfAnyBut(null, emptyChars));
assertEquals("indexOfAnyBut(str1, empty-char-array)", 0, StringUtils.indexOfAnyBut(str1, emptyChars));
assertEquals("indexOfAnyBut(empty-string, empty-char-array)", -1, StringUtils.indexOfAnyBut("", emptyChars));
assertEquals("indexOfAnyBut(empty-string, chars1)", -1, StringUtils.indexOfAnyBut("", chars1));
assertEquals("indexOfAnyBut(str1, chars1)", 0, StringUtils.indexOfAnyBut(str1, chars1));
assertEquals("indexOfAnyBut(str1, chars2)", -1, StringUtils.indexOfAnyBut(str1, chars2));
assertEquals("indexOfAnyBut(str1, chars3)", -1, StringUtils.indexOfAnyBut(str1, chars3));
assertEquals("indexOfAnyBut(str2, chars1)", -1, StringUtils.indexOfAnyBut(str2, chars1));
assertEquals("indexOfAnyBut(str2, chars2)", 0, StringUtils.indexOfAnyBut(str2, chars2));
assertEquals("indexOfAnyBut(str2, chars3)", -1, StringUtils.indexOfAnyBut(str2, chars3));
assertEquals("indexOfAnyBut(String3, chars1)", 0, StringUtils.indexOfAnyBut(str3, chars1));
assertEquals("indexOfAnyBut(String3, chars2)", 1, StringUtils.indexOfAnyBut(str3, chars2));
assertEquals("indexOfAnyBut(String3, chars3)", -1, StringUtils.indexOfAnyBut(str3, chars3));
}
public void testAbbreviate()
{
assertEquals("abbreviate(String,int) failed",