/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.core.util; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class StringUtil { private static final Log log = LogFactory.getLog(StringUtil.class); public static final String EMPTY_STRING = ""; /** * @param source The source string to perform replacements on. * @param find The substring to find in source. * @param replace The string to replace 'find' within source * * @return The source string, with all occurrences of 'find' replaced with 'replace' */ public static String replace(String source, String find, String replace) { if ((source == null) || (find == null) || (replace == null)) { return source; } int sourceLen = source.length(); int findLen = find.length(); if ((sourceLen == 0) || (findLen == 0)) { return source; } StringBuilder buffer = new StringBuilder(); int idx; int fromIndex; for (fromIndex = 0; (idx = source.indexOf(find, fromIndex)) != -1; fromIndex = idx + findLen) { buffer.append(source.substring(fromIndex, idx)); buffer.append(replace); } if (fromIndex == 0) { return source; } buffer.append(source.substring(fromIndex)); return buffer.toString(); } /** * @param source The source string to perform replacements on. * @param find The substring to find in source. * * @return The source string, with all occurrences of 'find' removed */ public static String remove(String source, String find) { if ((source == null) || (find == null)) { return source; } String retVal = null; int sourceLen = source.length(); int findLen = find.length(); StringBuilder remove = new StringBuilder(source); try { if ((sourceLen > 0) && (findLen > 0)) { int fromIndex; int idx; for (fromIndex = 0, idx = 0; (fromIndex = source.indexOf(find, idx)) != -1; idx = fromIndex + findLen) { remove.delete(fromIndex, findLen + fromIndex); } retVal = remove.toString(); } } catch (Exception e) { log.error("This should not have happened.", e); retVal = null; } return retVal; } /** * Print out everything in an Iterator in a user-friendly string format. * * @param i An iterator to print out. * @param delim The delimiter to use between elements. * * @return The Iterator's elements in a user-friendly string format. */ public static String iteratorToString(Iterator<?> i, String delim) { return iteratorToString(i, delim, ""); } /** * Print out everything in an Iterator in a user-friendly string format. * * @param i An iterator to print out. * @param delim The delimiter to use between elements. * @param quoteChar The character to quote each element with. * * @return The Iterator's elements in a user-friendly string format. */ public static String iteratorToString(Iterator<?> i, String delim, String quoteChar) { Object elt = null; StringBuilder rstr = new StringBuilder(); String s; while (i.hasNext()) { if (rstr.length() > 0) { rstr.append(delim); } elt = i.next(); if (elt == null) { rstr.append("NULL"); } else { s = elt.toString(); if (quoteChar != null) { rstr.append(quoteChar).append(s).append(quoteChar); } else { rstr.append(s); } } } return rstr.toString(); } /** * Print out a List in a user-friendly string format. * * @param list A List to print out. * @param delim The delimiter to use between elements. * * @return The List in a user-friendly string format. */ public static String listToString(List<?> list, String delim) { if (list == null) { return "NULL"; } Iterator<?> i = list.iterator(); return iteratorToString(i, delim, null); } public static String collectionToString(Collection<?> collection, String delim) { if (collection == null) { return "NULL"; } Iterator<?> i = collection.iterator(); return iteratorToString(i, delim, null); } /** * Print out a List in a user-friendly string format. * * @param list A List to print out. * * @return The List in a user-friendly string format. */ public static String listToString(List<?> list) { return listToString(list, ","); } public static String collectionToString(Collection<?> collection) { return collectionToString(collection, ","); } /** * Print out an array as a String */ public static String arrayToString(Object[] array) { return arrayToString(array, ','); } /** * Print out an array as a String */ public static String arrayToString(boolean[] array) { if (array == null) { return "null"; } String rstr = ""; char delim = ','; for (int i = 0; i < array.length; i++) { if (i > 0) { rstr += delim; } rstr += array[i]; } return rstr; } /** * Print out an array as a String * * @param array The array to print out * @param delim The delimiter to use between elements. */ public static String arrayToString(Object[] array, char delim) { if (array == null) { return "null"; } StringBuilder rstr = new StringBuilder(); for (int i = 0; i < array.length; i++) { if (i > 0) { rstr.append(delim); } rstr.append(array[i]); } return rstr.toString(); } /** * Print out an array as a String */ public static String arrayToString(int[] array) { if (array == null) { return "null"; } StringBuilder rstr = new StringBuilder(); for (int i = 0; i < array.length; i++) { if (i > 0) { rstr.append(","); } rstr.append(array[i]); } return rstr.toString(); } /** * Create a string formulated by inserting a delimiter in between consecutive array elements. * * @param objs List of objects to implode (elements may not be null) * @param delim String to place inbetween elements * * @return A string with objects in the list seperated by delim */ public static String implode(List<?> objs, String delim) { StringBuilder buf = new StringBuilder(); int size = objs.size(); for (int i = 0; i < (size - 1); i++) { buf.append(objs.get(i).toString()); buf.append(delim); } if (size != 0) { buf.append(objs.get(size - 1).toString()); } return buf.toString(); } /** * Split a string on delimiter boundaries, and place each element into a List. * * @param s String to split up * @param delim Delimiting token, ala StringTokenizer * * @return a List comprised of elements split by the tokenizing */ public static List<String> explode(String s, String delim) { List<String> res = new ArrayList<String>(); if (s == null) return res; StringTokenizer tok = new StringTokenizer(s, delim); while (tok.hasMoreTokens()) { res.add(tok.nextToken()); } return res; } /** * Split a string on delimiter boundaries, and place each element into an Array. * * @param toExplode String to split up * @param delim Delimiting token, ala StringTokenizer * * @return an Array comprised of elements split by the tokenizing */ public static String[] explodeToArray(String toExplode, String delim) { List<String> strings = explode(toExplode, delim); String[] ret; ret = strings.toArray(new String[strings.size()]); return ret; } /** * Split a string up by whitespace, taking into account quoted subcomponents. If there is an uneven number of * quotes, a parse error will be thrown. * * @param arg String to parse * * @return an array of elements, the argument was split into * * @throws IllegalArgumentException indicating there was a quoting error */ public static String[] explodeQuoted(String arg) throws IllegalArgumentException { List<String> res = new ArrayList<String>(); StringTokenizer quoteTok; boolean inQuote = false; arg = arg.trim(); quoteTok = new StringTokenizer(arg, "\"", true); while (quoteTok.hasMoreTokens()) { String elem = (String) quoteTok.nextElement(); if (elem.equals("\"")) { inQuote = !inQuote; continue; } if (inQuote) { res.add(elem); } else { StringTokenizer spaceTok = new StringTokenizer(elem.trim()); while (spaceTok.hasMoreTokens()) { res.add(spaceTok.nextToken()); } } } if (inQuote) { throw new IllegalArgumentException("Unbalanced quotation marks"); } return res.toArray(new String[res.size()]); } /** * Remove a prefix from a string. If value starts with prefix, it will be removed, the resultant string is trimmed * and returned. * * @return If value starts with prefix, then this method returns value with the prefix removed, and the resultant * string trimmed. If value does not start with prefix, value is returned as-is. */ public static String removePrefix(String value, String prefix) { if (!value.startsWith(prefix)) { return value; } return value.substring(prefix.length()).trim(); } /** * @return the plural of word. This is done by applying a few rules. These cover most (but not all) cases: 1. If the * word ends in s, ss, x, o, or ch, append es 2. If the word ends in a consonant followed by y, drop the y * and add ies 3. Append an s and call it a day. The ultimate references is at * http://en.wikipedia.org/wiki/English_plural */ public static String pluralize(String word) { if (word.endsWith("s") || word.endsWith("x") || word.endsWith("o") || word.endsWith("ch")) { return word + "es"; } if (word.endsWith("y")) { // Odd case to avoid StringIndexOutOfBounds later if (word.length() == 1) { return word; } // Check next-to-last letter char next2last = word.charAt(word.length() - 2); if ((next2last != 'a') && (next2last != 'e') && (next2last != 'i') && (next2last != 'o') && (next2last != 'u') && (next2last != 'y')) { return word.substring(0, word.length() - 1) + "ies"; } } return word + "s"; } /** * @return The stack trace for the given Throwable as a String. */ public static String getStackTrace(Throwable t) { if (t == null) { return "THROWABLE-WAS-NULL (at " + getStackTrace(new Exception()) + ")"; } try { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); Throwable cause = t.getCause(); if (cause != null) { return sw.toString() + getStackTrace(cause); } return sw.toString(); } catch (Exception e) { return "\n\nStringUtil.getStackTrace " + "GENERATED EXCEPTION: '" + e.toString() + "' \n\n"; } } /** * @return The stack trace for the given Throwable as a String. */ public static String getFirstStackTrace(Throwable t) { if (t == null) { return null; } StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } /** * @param s A string that might contain unix-style path separators. * * @return The correct path for this platform (i.e, if win32, replace / with \). */ public static String normalizePath(String s) { return StringUtil.replace(s, "/", File.separator); } public static String formatDuration(long duration) { return formatDuration(duration, 0, false); } public static String formatDuration(long duration, int scale, boolean minDigits) { long hours; long mins; int digits; double millis; hours = duration / 3600000; duration -= hours * 3600000; mins = duration / 60000; duration -= mins * 60000; millis = (double) duration / 1000; StringBuilder buf = new StringBuilder(); if ((hours > 0) || (minDigits == false)) { buf.append(((hours < 10) && (minDigits == false)) ? ("0" + hours) : String.valueOf(hours)).append(':'); minDigits = false; } if ((mins > 0) || (minDigits == false)) { buf.append(((mins < 10) && (minDigits == false)) ? ("0" + mins) : String.valueOf(mins)).append(':'); minDigits = false; } // Format seconds and milliseconds NumberFormat fmt = NumberFormat.getInstance(); digits = (((minDigits == false) || ((scale == 0) && (millis >= 9.5))) ? 2 : 1); fmt.setMinimumIntegerDigits(digits); fmt.setMaximumIntegerDigits(2); // Max of 2 fmt.setMinimumFractionDigits(0); // Don't need any fmt.setMaximumFractionDigits(scale); buf.append(fmt.format(millis)); return buf.toString(); } public static String repeatChars(char c, int nTimes) { char[] arr = new char[nTimes]; for (int i = 0; i < nTimes; i++) { arr[i] = c; } return new String(arr); } /** * Capitalizes the first letter of str. * * @param str The string to capitalize. * * @return A new string that is <code>str</code> capitalized. Returns <code>null</code> if str is null. */ public static String capitalize(String str) { if (str == null) { return null; } else if (str.trim().equals("")) { return str; } String result = str.substring(0, 1).toUpperCase() + str.substring(1, str.length()); return result; } public static String truncate(String s, int truncLength, boolean removeWhiteSpace) { String temp = ((s.length() > truncLength) ? (s.substring(0, truncLength) + "...") : s); if (removeWhiteSpace) { temp = temp.replaceAll("\\s+", " "); } return temp; } public static boolean isEmpty(String s) { return s == null || s.length() == 0; } public static boolean isNotEmpty(String s) { return !isEmpty(s); } public static boolean isBlank(String s) { return s == null || s.trim().length() == 0; } public static boolean isNotBlank(String s) { return !isBlank(s); } }