blob: 6fd84b25e017ef3b530979960396db755620a713 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.tools.ant.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Vector;
/**
* A set of helper methods related to string manipulation.
*
*/
public final class StringUtils {
private static final long KILOBYTE = 1024;
private static final long MEGABYTE = KILOBYTE * 1024;
private static final long GIGABYTE = MEGABYTE * 1024;
private static final long TERABYTE = GIGABYTE * 1024;
private static final long PETABYTE = TERABYTE * 1024;
/**
* constructor to stop anyone instantiating the class
*/
private StringUtils() {
}
/** the line separator for this OS */
public static final String LINE_SEP = System.getProperty("line.separator");
/**
* Splits up a string into a list of lines. It is equivalent
* to <tt>split(data, '\n')</tt>.
* @param data the string to split up into lines.
* @return the list of lines available in the string.
*/
public static Vector lineSplit(String data) {
return split(data, '\n');
}
/**
* Splits up a string where elements are separated by a specific
* character and return all elements.
* @param data the string to split up.
* @param ch the separator character.
* @return the list of elements.
*/
public static Vector split(String data, int ch) {
Vector elems = new Vector();
int pos = -1;
int i = 0;
while ((pos = data.indexOf(ch, i)) != -1) {
String elem = data.substring(i, pos);
elems.addElement(elem);
i = pos + 1;
}
elems.addElement(data.substring(i));
return elems;
}
/**
* Replace occurrences into a string.
* @param data the string to replace occurrences into
* @param from the occurrence to replace.
* @param to the occurrence to be used as a replacement.
* @return the new string with replaced occurrences.
*/
public static String replace(String data, String from, String to) {
StringBuffer buf = new StringBuffer(data.length());
int pos = -1;
int i = 0;
while ((pos = data.indexOf(from, i)) != -1) {
buf.append(data.substring(i, pos)).append(to);
i = pos + from.length();
}
buf.append(data.substring(i));
return buf.toString();
}
/**
* Convenient method to retrieve the full stacktrace from a given exception.
* @param t the exception to get the stacktrace from.
* @return the stacktrace from the given exception.
*/
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
pw.close();
return sw.toString();
}
/**
* Checks that a string buffer ends up with a given string. It may sound
* trivial with the existing
* JDK API but the various implementation among JDKs can make those
* methods extremely resource intensive
* and perform poorly due to massive memory allocation and copying. See
* @param buffer the buffer to perform the check on
* @param suffix the suffix
* @return <code>true</code> if the character sequence represented by the
* argument is a suffix of the character sequence represented by
* the StringBuffer object; <code>false</code> otherwise. Note that the
* result will be <code>true</code> if the argument is the
* empty string.
*/
public static boolean endsWith(StringBuffer buffer, String suffix) {
if (suffix.length() > buffer.length()) {
return false;
}
// this loop is done on purpose to avoid memory allocation performance
// problems on various JDKs
// StringBuffer.lastIndexOf() was introduced in jdk 1.4 and
// implementation is ok though does allocation/copying
// StringBuffer.toString().endsWith() does massive memory
// allocation/copying on JDK 1.5
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169
int endIndex = suffix.length() - 1;
int bufferIndex = buffer.length() - 1;
while (endIndex >= 0) {
if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) {
return false;
}
bufferIndex--;
endIndex--;
}
return true;
}
/**
* xml does not do "c" like interpretation of strings.
* i.e. \n\r\t etc.
* this method processes \n, \r, \t, \f, \\
* also subs \s -> " \n\r\t\f"
* a trailing '\' will be ignored
*
* @param input raw string with possible embedded '\'s
* @return converted string
* @since Ant 1.7
*/
public static String resolveBackSlash(String input) {
StringBuffer b = new StringBuffer();
boolean backSlashSeen = false;
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);
if (!backSlashSeen) {
if (c == '\\') {
backSlashSeen = true;
} else {
b.append(c);
}
} else {
switch (c) {
case '\\':
b.append((char) '\\');
break;
case 'n':
b.append((char) '\n');
break;
case 'r':
b.append((char) '\r');
break;
case 't':
b.append((char) '\t');
break;
case 'f':
b.append((char) '\f');
break;
case 's':
b.append(" \t\n\r\f");
break;
default:
b.append(c);
}
backSlashSeen = false;
}
}
return b.toString();
}
/**
* Takes a human readable size representation eg 10K
* a long value. Doesn't support 1.1K or other rational values.
* @param humanSize the amount as a human readable string.
* @return a long value representation
* @throws Exception if there is a problem.
* @since Ant 1.7
*/
public static long parseHumanSizes(String humanSize) throws Exception {
long factor = 1L;
char s = humanSize.charAt(0);
switch (s) {
case '+':
humanSize = humanSize.substring(1);
break;
case '-':
factor = -1L;
humanSize = humanSize.substring(1);
break;
default:
break;
}
//last character isn't a digit
char c = humanSize.charAt(humanSize.length() - 1);
if (!Character.isDigit(c)) {
int trim = 1;
switch (c) {
case 'K':
factor *= KILOBYTE;
break;
case 'M':
factor *= MEGABYTE;
break;
case 'G':
factor *= GIGABYTE;
break;
case 'T':
factor *= TERABYTE;
break;
case 'P':
factor *= PETABYTE;
break;
default:
trim = 0;
}
humanSize = humanSize.substring(0, humanSize.length() - trim);
}
return factor * Long.parseLong(humanSize);
}
/**
* Removes the suffix from a given string, if the string contains
* that suffix.
* @param string String for check
* @param suffix Suffix to remove
* @return the <i>string</i> with the <i>suffix</i>
*/
public static String removeSuffix(String string, String suffix) {
if (string.endsWith(suffix)) {
return string.substring(0, string.length() - suffix.length());
} else {
return string;
}
}
/**
* Removes the prefix from a given string, if the string contains
* that prefix.
* @param string String for check
* @param prefix Prefix to remove
* @return the <i>string</i> with the <i>prefix</i>
*/
public static String removePrefix(String string, String prefix) {
if (string.startsWith(prefix)) {
return string.substring(prefix.length());
} else {
return string;
}
}
}