// =========================================================================== // CONTENT : CLASS StringUtil // AUTHOR : Manfred Duchrow // VERSION : 2.0 - 21/03/2003 // HISTORY : // 10/07/1999 duma CREATED // 09/12/1999 duma added -> SPACE, repeat() // moved -> from package com.mdcs.util // 25/01/2000 duma moved -> from package com.mdcs.text // 09/02/2000 duma changed -> renamed SPACE to CH_SPACE // added -> CH_CR, CH_TAB, ..., STR_SPACE, STR_NEWLINE, ... // 11/01/2002 duma added -> indexOf(), indexOfIgnoreCase(), contains(), containsIgnoreCase() // 17/05/2002 duma added -> copyFrom() // 03/07/2002 duma added -> cutHead(), prefix(), suffix() // 06/07/2002 duma added -> indexOf() and contains() for StringPattern and reverse() // 15/08/2002 duma added -> upTo(), startingFrom(), asMap() // 29/09/2002 duma added -> allParts() and allSubstrings() that don't skip empty elements // 06/03/2003 duma changed -> append() now uses System.arraycopy() // added -> remove( String[], String[] ), remove( String[], String ) // removeNull( String[] ) // 21/03/2003 duma added -> leftPad(), leftPadCh(), rightPad(), rightPadCh() for int values // // Copyright (c) 1999-2003, by Manfred Duchrow. All rights reserved. // =========================================================================== package org.pf.text; // =========================================================================== // IMPORT // =========================================================================== import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.ArrayList; import java.io.PrintWriter; import java.io.StringWriter; /** * The sole instance of this class provides several convienience methods * for string manipulation such as substring replacement or character repetition. * * @author Manfred Duchrow * @version 2.0 */ public class StringUtil { // ========================================================================= // CONSTANTS // ========================================================================= /** Constant for the space character **/ public static final char CH_SPACE = '\u0020' ; /** Constant for the new line character **/ public static final char CH_NEWLINE = '\n' ; /** Constant for the carriage return character **/ public static final char CH_CR = '\r' ; /** Constant for the tabulator character **/ public static final char CH_TAB = '\t' ; /** Constant for the String representation of the space character **/ public static final String STR_SPACE = "\u0020" ; /** Constant for the String representation of the new line character **/ public static final String STR_NEWLINE = "\n" ; /** Constant for the String representation of the carriage return character **/ public static final String STR_CR = "\r" ; /** Constant for the String representation of the tabulator character **/ public static final String STR_TAB = "\t" ; private static final String WORD_DELIM = STR_SPACE + STR_TAB + STR_NEWLINE + STR_CR ; // ========================================================================= // CLASS VARIABLES // ========================================================================= private static StringUtil singleton = null ; private static StringUtil getSingleton() { return singleton ; } private static void setSingleton( StringUtil inst ) { singleton = inst ; } // ========================================================================= // PUBLIC CLASS METHODS // ========================================================================= /** * Returns the one and only instance of this class. */ public static StringUtil current() { if ( getSingleton() == null ) setSingleton( new StringUtil() ) ; return getSingleton() ; } // current() // ========================================================================= // PUBLIC INSTANCE METHODS // ========================================================================= /** * Returns the given string with all found oldSubStr replaced by newSubStr. <br> * * Example: StringUtil.current().replaceAll( "Seven of ten", "even", "ix" ) ;<br> * results in: "Six of ten" * * @param sourceStr The string that should be checked for occurrences of oldSubStr * @param oldSubStr The string that is searched for in sourceStr * @param newSubStr The new string that is placed everywhere the oldSubStr was found * @return The original string with all found substrings replaced by new strings */ public String replaceAll( String sourceStr, String oldSubStr, String newSubStr ) { String part = null ; String result = "" ; int index = -1 ; int subLen = 0 ; subLen = oldSubStr.length() ; part = sourceStr ; while ( ( part.length() > 0 ) && ( subLen > 0 ) ) { index = part.indexOf( oldSubStr ) ; if ( index >= 0 ) { result = result + part.substring( 0, index ) + newSubStr ; part = part.substring( index + subLen ) ; } else { result = result + part ; part = "" ; } } // while return result ; } // replaceAll() // ------------------------------------------------------------------------- /** * Returns a string with size of count and all characters initialized with ch. <br> * * @param ch the character to be repeated in the result string. * @param count the number of times the given character should occur in the result string. * @return A string containing <i>count</i> characters <i>ch</i>. */ public String repeat( char ch, int count ) { StringBuffer buffer = null ; buffer = new StringBuffer( count ) ; for ( int i = 1 ; i <= count ; i++ ) { buffer.append( ch ) ; } return ( buffer.toString() ) ; } // repeat() // ------------------------------------------------------------------------- /** * Returns an array of substrings of the given text. <br> * The delimiters between the substrings are the whitespace characters * SPACE, NEWLINE, CR and TAB. * * @see #parts(String, String) * @param text The string that should be splitted into whitespace separated words * @return An array of substrings of the given text */ public String[] words( String text ) { return this.parts( text, WORD_DELIM ) ; } // words() // ------------------------------------------------------------------------- /** * Returns an array of substrings of the given text. <br> * The separators between the substrings are the given delimiters. * Each character in the delimiter string is treated as a separator. * <br> * All consecutive delimiters are treated as one delimiter, that is there * will be no empty strings in the result. * * @see #allParts(String, String) * @see #substrings(String, String) * @see #allSubstrings(String, String) * @param text The string that should be splitted into substrings * @param delimiters All characters that should be recognized as a separator or substrings * @return An array of substrings of the given text */ public String[] parts( String text, String delimiters ) { return this.parts( text, delimiters, false ) ; } // parts() // ------------------------------------------------------------------------- /** * Returns an array of substrings of the given text. <br> * The separators between the substrings are the given delimiters. * Each character in the delimiter string is treated as a separator. * <br> * For each delimiter that is followed immediately by another delimiter an * empty string will be added to the result. There are no empty strings added * to the result for a delimiter at the very beginning of at the very end. * <p> * Examples: * <p> * allParts( "/A/B//", "/" ) --> { "A", "B", "" } <br> * allParts( "/A,B/C;D", ",;/" ) --> { "A", "B", "C", "D" } <br> * allParts( "A/B,C/D", "," ) --> { "A/B", "C/D" } <br> * * @see #parts(String, String) * @see #substrings(String, String) * @see #allSubstrings(String, String) * @param text The string that should be splitted into substrings * @param delimiters All characters that should be recognized as a separator or substrings * @return An array of substrings of the given text */ public String[] allParts( String text, String delimiters ) { return this.parts( text, delimiters, true ) ; } // allParts() // ------------------------------------------------------------------------- /** * Returns the given text split up into an array of strings, at * the occurrances of the separator string. * * In contrary to method parts() the separator is a one or many * character sequence delimiter. That is, only the exact sequence * of the characters in separator identifies the end of a substring. * Subsequent occurences of separator will be skipped. Therefore * no empty strings ("") will be in the result array. * * @see #allSubstrings(String, String) * @see #parts(String, String) * @see #allParts(String, String) * @param text The text to be split up * @param separator The string that separates the substrings * @return An array of substrings not containing any separator anymore */ public String[] substrings( String text, String separator ) { return this.substrings( text, separator, false ) ; } // substrings() // ------------------------------------------------------------------------- /** * Returns the given text split up into an array of strings, at * the occurrances of the separator string. * * In contrary to method allParts() the separator is a one or many * character sequence delimiter. That is, only the exact sequence * of the characters in separator identifies the end of a substring. * Subsequent occurences of separator are not skipped. They are added * as empty strings to the result. * * @see #substrings(String, String) * @see #parts(String, String) * @see #allParts(String, String) * @param text The text to be split up * @param separator The string that separates the substrings * @return An array of substrings not containing any separator anymore */ public String[] allSubstrings( String text, String separator ) { return this.substrings( text, separator, true ) ; } // allSubstrings() // ------------------------------------------------------------------------- /** * Returns the first substring that is enclosed by the specified delimiters. * <br> * The delimiters are not included in the return string. * <p> * Example:<br> * getDelimitedSubstring( "This {placeholder} belongs to me", "{", "}" ) * --> returns "placeholder" * * @param text The input string that contains the delimited part * @param startDelimiter The start delimiter of the substring * @param endDelimiter The end delimiter of the substring * @return The substring or an empty string, if no delimiters are found. */ public String getDelimitedSubstring( String text, String startDelimiter, String endDelimiter ) { int start ; int stop ; String subStr = "" ; if ( ( text != null ) && ( startDelimiter != null ) && ( endDelimiter != null ) ) { start = text.indexOf( startDelimiter ) ; if ( start >= 0 ) { stop = text.indexOf( endDelimiter, start + 1 ) ; if ( stop > start ) subStr = text.substring( start + 1, stop ) ; } } return subStr ; } // getDelimitedSubstring() // ------------------------------------------------------------------------- /** * Returns the first substring that is enclosed by the specified delimiter. <br> * The delimiters are not included in the return string. * <p> * Example:<br> * getDelimitedSubstring( "File 'text.txt' not found.", "'", "'" ) * --> returns "text.txt" * * @param text The input string that contains the delimited part * @param delimiter The start and end delimiter of the substring * @return The substring or an empty string, if no delimiters are found. */ public String getDelimitedSubstring( String text, String delimiter ) { return this.getDelimitedSubstring( text, delimiter, delimiter ) ; } // getDelimitedSubstring() // ------------------------------------------------------------------------- /** * Prints the stack trace of the specified throwable to a * string and returns it. */ public String stackTrace( Throwable throwable ) { StringWriter sw = new StringWriter() ; PrintWriter pw = new PrintWriter( sw ) ; throwable.printStackTrace( pw ) ; pw.close() ; return sw.toString() ; } // stackTrace() // ------------------------------------------------------------------------- /** * Returns the given string filled (on the left) up to the specified * length with the given character. <br> * Example: leftPadCh( "12", 6, '0' ) --> "000012" */ public String leftPadCh( String str, int len, char ch ) { return this.padCh( str, len, ch, true ) ; } // leftPadCh() // ------------------------------------------------------------------------- /** * Returns the given string filled (on the left) up to the specified * length with spaces. <br> * Example: leftPad( "XX", 4 ) --> " XX" * * @param str The string that has to be filled up to the specified length * @param len The length of the result string */ public String leftPad( String str, int len ) { return this.leftPadCh( str, len, CH_SPACE ) ; } // leftPad() // ------------------------------------------------------------------------- /** * Returns the given integer as string filled (on the left) up to the * specified length with the given fill character. <br> * Example: leftPad( 24, 5, '*' ) --> "***24" */ public String leftPadCh( int value, int len, char fillChar ) { return this.leftPadCh( Integer.toString(value), len, fillChar ) ; } // leftPadCh() // ------------------------------------------------------------------------- /** * Returns the given integer as string filled (on the left) up to the * specified length with zeroes. <br> * Example: leftPad( 12, 4 ) --> "0012" */ public String leftPad( int value, int len ) { return this.leftPadCh( value, len, '0' ) ; } // leftPad() // ------------------------------------------------------------------------- /** * Returns the given string filled (on the right) up to the specified * length with the given character. <br> * Example: rightPadCh( "34", 5, 'X' ) --> "34XXX" */ public String rightPadCh( String str, int len, char ch ) { return this.padCh( str, len, ch, false ) ; } // rightPadCh() // ------------------------------------------------------------------------- /** * Returns the given string filled (on the right) up to the specified * length with spaces. <br> * Example: rightPad( "88", 6 ) --> "88 " */ public String rightPad( String str, int len ) { return this.rightPadCh( str, len, CH_SPACE ) ; } // rightPad() // ------------------------------------------------------------------------- /** * Returns the given integer as string filled (on the right) up to the * specified length with the given character. <br> * Example: rightPad( "32", 4, '#' ) --> "32##" */ public String rightPadCh( int value, int len, char fillChar ) { return this.rightPadCh( Integer.toString(value), len, fillChar ) ; } // rightPad() // ------------------------------------------------------------------------- /** * Returns the given integer as string filled (on the right) up to the * specified length with spaces. <br> * Example: rightPad( "17", 5 ) --> "17 " */ public String rightPad( int value, int len ) { return this.rightPadCh( value, len, CH_SPACE ) ; } // rightPad() // ------------------------------------------------------------------------- /** * Returns the given string filled equally left and right * up to the specified length with the given character. <br> * Example: centerCh( "A", 5, '_' ) --> "__A__" <br> * Example: centerCh( "XX", 7, '+' ) --> "++XX+++" */ public String centerCh( String str, int len, char ch ) { String buffer = null ; int missing = len - str.length() ; int half = 0 ; if ( missing <= 0 ) return str ; half = missing / 2 ; buffer = this.rightPadCh( str, len-half, ch ) ; return this.leftPadCh( buffer, len, ch ) ; } // centerCh() // ------------------------------------------------------------------------- /** * Returns the given string filled (on the right and right) * up to the specified length with spaces. <br> * Example: center( "Mike", 10 ) --> " Mike " */ public String center( String str, int len ) { return this.centerCh( str, len, CH_SPACE ) ; } // center() // ------------------------------------------------------------------------- /** * Returns the given string array extended by one element * that hold the specified string. */ public String[] append( String[] strings, String string ) { String[] appStr = { string } ; return this.append( strings, appStr ) ; } // append() // ------------------------------------------------------------------------- /** * Returns an array of strings that contains all strings given * by the first and second string array. The strings from the * second array will be added at the end of the first array. * * @param strings The array of string to which to append * @param appendStrings The string to be appended to the first array */ public String[] append( String[] strings, String[] appendStrings ) { String[] newStrings = null ; if ( strings == null ) return appendStrings ; if ( appendStrings == null ) return strings ; newStrings = new String[strings.length + appendStrings.length] ; System.arraycopy( strings, 0, newStrings, 0, strings.length ) ; System.arraycopy( appendStrings, 0, newStrings, strings.length, appendStrings.length ) ; return newStrings ; } // append() // ------------------------------------------------------------------------- /** * Returns an array of strings that contains all strings given * in the first plus the specified string to append, if it is not * already in the given array. */ public String[] appendIfNotThere( String[] strings, String appendString ) { if ( this.contains( strings, appendString ) ) return strings ; else return this.append( strings, appendString ) ; } // appendIfNotThere() // ------------------------------------------------------------------------- /** * Returns an array of strings that contains all strings given * in the first plus all strings of the second array that are not * already in the first array. */ public String[] appendIfNotThere( String[] strings, String[] appendStrings ) { String[] newStrings = strings ; if ( appendStrings == null ) return newStrings ; for ( int i = 0 ; i < appendStrings.length ; i++ ) { newStrings = this.appendIfNotThere( newStrings, appendStrings[i] ) ; } return newStrings ; } // appendIfNotThere() // ------------------------------------------------------------------------- /** * Removes all string of the second array from the first array. * Returns a new array of string that contains all remaining strings of the * original strings array. * * @param strings The array from which to remove the strings * @param removeStrings The strings to be removed */ public String[] remove( String[] strings, String[] removeStrings ) { if ( ( strings == null ) || ( removeStrings == null ) || ( strings.length == 0 ) || ( removeStrings.length == 0 ) ) { return strings ; } return this.removeFromStringArray( strings, removeStrings ) ; } // remove() // ------------------------------------------------------------------------- /** * Removes the given string from the specified string array. * Returns a new array of string that contains all remaining strings of the * original strings array. * * @param strings The array from which to remove the string * @param removeString The string to be removed */ public String[] remove( String[] strings, String removeString ) { String[] removeStrings = { removeString } ; return this.remove( strings, removeStrings ) ; } // remove() // ------------------------------------------------------------------------- /** * Removes all null values from the given string array. * Returns a new string array that contains all none null values of the * input array. * * @param strings The array to be cleared of null values */ public String[] removeNull( String[] strings ) { if ( strings == null ) return strings ; return this.removeFromStringArray( strings, null ) ; } // removeNull() // ------------------------------------------------------------------------- /** * Returns a string that contains all given strings concatenated * and separated by the specified separator. * * @param strings The array of strings that should be concatenated * @param separator The separator between the strings * @return One string containing the concatenated strings separated by separator */ public String asString ( String[] strings, String separator ) { StringBuffer buffer = null ; buffer = new StringBuffer( strings.length * 20 ) ; if ( strings.length > 0 ) { buffer.append( strings[0].toString() ) ; for ( int i = 1 ; i < strings.length ; i++ ) { buffer.append( separator ) ; if ( strings[i] != null ) buffer.append( strings[i] ) ; } } return buffer.toString() ; } // asString() // ------------------------------------------------------------------------- /** * Returns a string that contains all given strings concatenated * and separated by comma. * * @param strings The array of strings that should be concatenated * @return One string containing the concatenated strings separated by comma (",") */ public String asString ( String[] strings ) { return this.asString( strings, "," ) ; } // asString() // ------------------------------------------------------------------------- /** * Returns the index of the first string in the given string array that * matches the specified string pattern. * If no string is found in the array the result is -1. * * @param strArray An array of string (may contain null elements) * @param pattern The pattern the searched string must match * @return The index of the matching string in the array or -1 if not found */ public int indexOf( String[] strArray, StringPattern pattern ) { if ( ( strArray == null ) || ( strArray.length == 0 ) ) return -1 ; boolean found = false ; for ( int i = 0 ; i < strArray.length ; i++ ) { if ( strArray[i] == null ) { if ( pattern == null ) found = true ; } else { if ( pattern != null ) found = pattern.matches( strArray[i] ) ; } if ( found ) return i ; } return -1 ; } // indexOf() // ------------------------------------------------------------------------- /** * Returns the index of the specified string in the given string array. * It returns the index of the first occurrence of the string. * If the string is not found in the array the result is -1. * The comparison of the strings is case-sensitive! * * @param strArray An array of string (may contain null elements) * @param searchStr The string to be looked up in the array (null allowed) * @return The index of the string in the array or -1 if not found */ public int indexOf( String[] strArray, String searchStr ) { return this.indexOfString( strArray, searchStr, false ) ; } // indexOf() // ------------------------------------------------------------------------- /** * Returns the index of the specified string in the given string array. * It returns the index of the first occurrence of the string. * If the string is not found in the array the result is -1. * The comparison of the strings is case-insensitive! * * @param strArray An array of string (may contain null elements) * @param searchStr The string to be looked up in the array (null allowed) * @return The index of the string in the array or -1 if not found */ public int indexOfIgnoreCase( String[] strArray, String searchStr ) { return this.indexOfString( strArray, searchStr, true ) ; } // indexOfIgnoreCase() // ------------------------------------------------------------------------- /** * Returns whether or not the specified string can be found * in the given string array. * * @param strArray An array of string (may contain null elements) * @param searchStr The string to be looked up in the array (null allowed) * @param ignoreCase Defines whether or not the comparison is case-sensitive. * @return true, if the specified array contains the given string */ public boolean contains( String[] strArray, String searchStr, boolean ignoreCase ) { if ( ignoreCase ) return this.containsIgnoreCase( strArray, searchStr ) ; else return this.contains( strArray, searchStr ) ; } // contains() // ------------------------------------------------------------------------- /** * Returns whether or not a string can be found in the given string array * that matches the specified string pattern. * * @param strArray An array of string (may contain null elements) * @param pattern The string pattern to match against in the array (null allowed) * @return true, if the specified array contains a string matching the pattern */ public boolean contains( String[] strArray, StringPattern pattern) { return ( this.indexOf( strArray, pattern ) >= 0 ) ; } // contains() // ------------------------------------------------------------------------- /** * Returns whether or not the specified string can be found * in the given string array. * The comparison of the strings is case-sensitive! * * @param strArray An array of string (may contain null elements) * @param searchStr The string to be looked up in the array (null allowed) * @return true, if the specified array contains the given string */ public boolean contains( String[] strArray, String searchStr ) { return ( this.indexOf( strArray, searchStr ) >= 0 ) ; } // contains() // ------------------------------------------------------------------------- /** * Returns whether or not the specified string can be found * in the given string array. * The comparison of the strings is case-insensitive! * * @param strArray An array of string (may contain null elements) * @param searchStr The string to be looked up in the array (null allowed) * @return true, if the specified array contains the given string */ public boolean containsIgnoreCase( String[] strArray, String searchStr ) { return ( this.indexOfIgnoreCase( strArray, searchStr ) >= 0 ) ; } // containsIgnoreCase() // ------------------------------------------------------------------------- /** * Returns all elements of string array <i>from</i> in a new array * from index start up to the end. * If start index is larger than the array's length, an empty array will be * returned. * * @param from The string array the elements should be copied from * @param start Index of the first element to copy */ public String[] copyFrom( String[] from, int start ) { if ( from == null ) return null ; return this.copyFrom( from, start, from.length - 1 ) ; } // copyFrom() // ------------------------------------------------------------------------- /** * Returns all elements of string array <i>from</i> in a new array * from index start up to index end (inclusive). * If end is larger than the last valid index, it will be reduced * to the last index. * If end index is less than start index, an empty array will be * returned. * * @param from The string array the elements should be copied from * @param start Index of the first element to copy * @param end Index of last element to be copied */ public String[] copyFrom( String[] from, int start, int end ) { String[] result ; int count ; int stop = end ; if ( from == null ) return null ; if ( stop > ( from.length - 1 ) ) stop = from.length - 1 ; count = stop - start + 1 ; if ( count < 1 ) return new String[0] ; result = new String[count] ; System.arraycopy( from, start, result, 0, count ) ; return result ; } // copyFrom() // ------------------------------------------------------------------------- /** * Returns the portion of the given string that comes before the last * occurance of the specified separator. <br> * If the separator could not be found in the given string, then the * string is returned unchanged. * <p> * Examples: * <p> * cutTail( "A/B/C", "/" ) ; // returns "A/B" * <br> * cutTail( "A/B/C", "," ) ; // returns "A/B/C" * <p> * @see #prefix( String, String ) * @see #suffix( String, String ) * @see #cutHead( String, String ) * @see #startingFrom( String, String ) * @see #upTo( String, String ) * @param text The string from which to cut off the tail * @param separator The separator from where to cut off * @return the string without the separator and without the characters after the separator */ public String cutTail( String text, String separator ) { int index ; if ( ( text == null ) || ( separator == null ) ) return text ; index = text.lastIndexOf( separator ) ; if ( index < 0 ) return text ; return text.substring( 0, index ) ; } // cutTail() // ------------------------------------------------------------------------ /** * Returns the portion of the given string that stands after the last * occurance of the specified separator. <br> * If the separator could not be found in the given string, then the * string is returned unchanged. * <p> * Examples: * <p> * cutHead( "A/B/C", "/" ) ; // returns "C" * <br> * cutHead( "A/B/C", "," ) ; // returns "A/B/C" * <p> * @see #prefix( String, String ) * @see #cutTail( String, String ) * @see #suffix( String, String ) * @see #startingFrom( String, String ) * @see #upTo( String, String ) * @param text The string from which to cut off the head * @param separator The separator up to which to cut off * @return the string without the separator and without the characters before the separator */ public String cutHead( String text, String separator ) { int index ; if ( ( text == null ) || ( separator == null ) ) return text ; index = text.lastIndexOf( separator ) ; if ( index < 0 ) return text ; return text.substring( index + 1 ) ; } // cutHead() // ------------------------------------------------------------------------ /** * Returns a string array with two elements where the first is the attribute * name and the second is the attribute value. * Splits the given string at the first occurance of separator and returns * the piece before the separator in element 0 and the piece after the * separator in the returned array. * If the separator is not found, the first element contains the full * string and the second an empty string. * * @param str The string that contains the name-value pair * @param separator The separator between name and value */ public String[] splitNameValue( String str, String separator ) { String[] result = { "", "" } ; int index ; if ( str != null ) { index = str.indexOf( separator ) ; if ( index > 0 ) { result[0] = str.substring( 0, index ) ; result[1] = str.substring( index + separator.length() ) ; } else { result[0] = str ; } } return result ; } // splitNameValue() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes before the * first occurance of the specified separator. * If the string starts with a separator, the result will be an empty string. * If the string doesn't contain the separator the method returns null. * <p> * Examples: * <p> * prefix( "A/B/C", "/" ) ; // returns "A" * <br> * prefix( "A/B/C", "," ) ; // returns null * <p> * @see #suffix( String, String ) * @see #cutTail( String, String ) * @see #cutHead( String, String ) * @see #startingFrom( String, String ) * @see #upTo( String, String ) * @param str The string of which the prefix is desired * @param separator Separates the prefix from the rest of the string */ public String prefix( String str, String separator ) { return this.prefix( str, separator, true ) ; } // prefix() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes after the * first occurance of the specified separator. * If the string ends with a separator, the result will be an empty string. * If the string doesn't contain the separator the method returns null. * <p> * Examples: * <p> * suffix( "A/B/C", "/" ) ; // returns "B/C" * <br> * suffix( "A/B/C", "," ) ; // returns null * <p> * @see #prefix( String, String ) * @see #cutTail( String, String ) * @see #cutHead( String, String ) * @see #startingFrom( String, String ) * @see #upTo( String, String ) * @param str The string of which the suffix is desired * @param separator Separates the suffix from the rest of the string */ public String suffix( String str, String separator ) { return this.suffix( str, separator, true ) ; } // suffix() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes before the * first occurance of the specified separator. * If the string starts with a separator, the result will be an empty string. * If the string doesn't contain the separator the method returns the * whole string unchanged. * <p> * Examples: * <p> * upTo( "A/B/C", "/" ) ; // returns "A" * <br> * upTo( "A/B/C", "," ) ; // returns "A/B/C" * <br> * upTo( "/A/B/C", "/" ) ; // returns "" * <p> * @see #prefix( String, String ) * @see #cutTail( String, String ) * @see #cutHead( String, String ) * @see #startingFrom( String, String ) * @see #suffix( String, String ) * @param str The string of which the prefix is desired * @param separator Separates the prefix from the rest of the string */ public String upTo( String str, String separator ) { return this.prefix( str, separator, false ) ; } // upTo() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes after the * first occurance of the specified separator. * If the string doesn't contain the separator the method returns the * whole string unchanged. * <p> * Examples: * <p> * startingFrom( "A/B/C", "/" ) ; // returns "B/C" * <br> * startingFrom( "A/B/C", "," ) ; // returns "A/B/C" * <p> * @see #prefix( String, String ) * @see #cutTail( String, String ) * @see #cutHead( String, String ) * @see #suffix( String, String ) * @see #upTo( String, String ) * @param str The string of which the suffix is desired * @param separator Separates the suffix from the rest of the string */ public String startingFrom( String str, String separator ) { return this.suffix( str, separator, false ) ; } // startingFrom() // ------------------------------------------------------------------------- /** * Returns a string that contains all characters of the given string in * reverse order. */ public String reverse( String str ) { if ( str == null ) return null ; char[] newStr = new char[str.length()] ; StringCharacterIterator iterator = new StringCharacterIterator(str) ; int i = 0 ; for(char ch = iterator.last(); ch != CharacterIterator.DONE; ch = iterator.previous()) { newStr[i] = ch ; i++ ; } return new String( newStr ) ; } // reverse() // ------------------------------------------------------------------------- /** * Returns the given map with new entries from the specified String. * If the specified map is null a new empty java.util.Hashtable will be * created. * <br> * The string is split up into elements separated by the elementSeparator * parameter. If this parameter is null the default separator "," is used. * <br> * After that each part is split up to a key-value pair separated by the * keyValueSeparator parameter. If this parameter is null the default "=" is * used. * <br> * Then the key-value pairs are added to the map and the map is returned. * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param elementSeparator The separator between the elements of the list * @param keyValueSeparator The separator between the keys and values * @param map The map to which the key-value pairs are added */ public Map toMap( String str, String elementSeparator, String keyValueSeparator, Map map ) { Map result ; String elemSep ; String kvSep ; String[] assignments ; String[] nameValue ; if ( str == null ) return map ; result = ( map == null ? new Hashtable() : map ) ; elemSep = ( elementSeparator == null ) ? "," : elementSeparator ; kvSep = ( keyValueSeparator == null ) ? "=" : keyValueSeparator ; assignments = this.parts( str, elemSep ) ; for ( int i = 0 ; i < assignments.length ; i++ ) { nameValue = this.splitNameValue( assignments[i], kvSep ) ; nameValue[0] = nameValue[0].trim() ; nameValue[1] = nameValue[1].trim() ; if ( nameValue[0].length() > 0 ) result.put( nameValue[0], nameValue[1] ) ; } return result ; } // asMap() // ------------------------------------------------------------------------- /** * Returns a new map object that contains all key-value pairs of the * specified string. * <br> * The separator between the elements is assumed to be "," * and "=" between key and value. * <p> * Example:<br> * "main=Fred,support1=John,support2=Stella,manager=Oscar" * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string with the list of key-value pairs */ public Map asMap( String str ) { return this.toMap( str, null, null, null ) ; } // asMap() // ------------------------------------------------------------------------- /** * Returns a new map object that contains all key-value pairs of the * specified string. * <br> * The separator between the keys and values is assumed to be "=". * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param elementSeparator The separator between the elements of the list */ public Map asMap( String str, String elementSeparator ) { return this.toMap( str, elementSeparator, null, null ) ; } // asMap() // ------------------------------------------------------------------------- /** * Returns a new map object that contains all key-value pairs of the * specified string. * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param elementSeparator The separator between the elements of the list * @param keyValueSeparator The separator between the keys and values */ public Map asMap( String str, String elementSeparator, String keyValueSeparator ) { return this.toMap( str, elementSeparator, keyValueSeparator, null ) ; } // asMap() // ------------------------------------------------------------------------- /** * Returns the given map object with all key-value pairs of the * specified string added to it. * <br> * The separator between the keys and values is assumed to be "=". * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param elementSeparator The separator between the elements of the list * @param map The map to which the key-value pairs are added */ public Map toMap( String str, String elementSeparator, Map map ) { return this.toMap( str, elementSeparator, null, map ) ; } // toMap() // ------------------------------------------------------------------------- /** * Adds all key-value pairs of the given string to the specified map. * <br> * The separator between the elements is assumed to be "," * and "=" between key and value. * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param map The map to which the key-value pairs are added */ public Map toMap( String str, Map map ) { return this.toMap( str, null, null, map ) ; } // toMap() // ------------------------------------------------------------------------- /** * Adds all key-value pairs of the given string to a new properties object. * <br> * The separator between the elements is assumed to be "," * and "=" between key and value. * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs */ public Properties asProperties( String str ) { return this.toProperties( str, null ) ; } // asProperties() // ------------------------------------------------------------------------- /** * Adds all key-value pairs of the given string to the specified properties. * <br> * The separator between the elements is assumed to be "," * and "=" between key and value. * <p> * <b>Be aware that all leading and trailing whitespaces of keys and values * will be removed!</b> * * @param str The string that contains the list of key-value pairs * @param properties The properties where the key-value pairs should be added */ public Properties toProperties( String str, Properties properties ) { Properties props = ( properties == null ) ? new Properties() : properties ; return (Properties)this.toMap( str, null, null, props ) ; } // toProperties() // ------------------------------------------------------------------------- // ========================================================================= // PROTECTED INSTANCE METHODS // ========================================================================= /** * Cuts off all leading and trailing occurences of separator in text. */ protected String trimSeparator( String text, String separator ) { int sepLen = separator.length() ; while ( text.startsWith( separator ) ) text = text.substring( separator.length() ) ; while ( text.endsWith( separator ) ) text = text.substring( 0, text.length() - sepLen ) ; return text ; } // trimSeparator() // ------------------------------------------------------------------------- /** * Returns an array of substrings of the given text. <br> * The separators between the substrings are the given delimiters. * Each character in the delimiter string is treated as a separator. * * @param text The string that should be splitted into substrings * @param delimiters All characters that should be recognized as a separator or substrings * @param all If true, empty elements will be returned, otherwise thye are skipped * @return An array of substrings of the given text */ protected String[] parts( String text, String delimiters, boolean all ) { ArrayList result = null ; StringTokenizer tokenizer = null ; if ( text == null ) return null ; if ( ( delimiters == null ) || ( delimiters.length() == 0 ) ) { String[] resultArray = { text } ; return resultArray ; } if ( text.length() == 0 ) { return new String[0] ; } else { result = new ArrayList() ; tokenizer = new StringTokenizer( text, delimiters, all ) ; if ( all ) this.collectParts( result, tokenizer, delimiters ) ; else this.collectParts( result, tokenizer ) ; } return (String[])result.toArray( new String[0] ) ; } // parts() // ------------------------------------------------------------------------- protected void collectParts( List list, StringTokenizer tokenizer ) { while( tokenizer.hasMoreTokens() ) { list.add( tokenizer.nextToken() ) ; } } // collectParts() // ------------------------------------------------------------------------- protected void collectParts( List list, StringTokenizer tokenizer, String delimiter ) { String token ; boolean lastWasDelimiter = false ; while( tokenizer.hasMoreTokens() ) { token = tokenizer.nextToken() ; if ( delimiter.indexOf( token ) >= 0 ) { if ( lastWasDelimiter ) list.add( "" ) ; lastWasDelimiter = true ; } else { list.add( token ) ; lastWasDelimiter = false ; } } } // collectParts() // ------------------------------------------------------------------------- /** * Returns the given text split up into an array of strings, at * the occurrances of the separator string. * * In contrary to method parts() the separator is a one or many * character sequence delimiter. That is, only the exact sequence * of the characters in separator identifies the end of a substring. * Parameter all defines whether empty strings between consecutive * separators are added to the result or not. * * @see #parts(String, String, boolean) * @param text The text to be split up * @param separator The string that separates the substrings * @param all If true, empty strings are added, otherwise skipped * @return An array of substrings not containing any separator anymore */ protected String[] substrings( String text, String separator, boolean all ) { int index = 0 ; int start = 0 ; int sepLen = 0 ; int strLen = 0 ; String str = text ; ArrayList strings = new ArrayList() ; if ( text == null ) return new String[0] ; if ( ( separator == null ) || ( separator.length() == 0 ) ) { if ( text.length() == 0 ) return new String[0] ; String[] resultArray = { text } ; return resultArray ; } if ( ! all ) str = this.trimSeparator( text, separator ) ; strLen = str.length() ; if ( strLen > 0 ) { sepLen = separator.length() ; index = str.indexOf( separator, start ) ; while ( index >= 0 ) { if ( all ) { if ( index > 0 ) { strings.add( str.substring( start, index ) ) ; } } else { if ( index > ( start + sepLen ) ) strings.add( str.substring( start, index ) ) ; } start = index + sepLen ; index = str.indexOf( separator, start ) ; } if ( start < strLen ) strings.add( str.substring( start ) ) ; } return (String[])strings.toArray( new String[0] ) ; } // substrings() // ------------------------------------------------------------------------- protected String padCh( String str, int len, char ch, boolean left ) { StringBuffer buffer = null ; int missing = len - str.length() ; if ( missing <= 0 ) return str ; buffer = new StringBuffer( len ) ; if ( ! left ) buffer.append( str ) ; for ( int i = 1 ; i <= missing ; i++ ) buffer.append( ch ) ; if ( left ) buffer.append( str ) ; return buffer.toString() ; } // padCh() // ------------------------------------------------------------------------- protected int indexOfString( String[] strArray, String searchStr, boolean ignoreCase ) { if ( ( strArray == null ) || ( strArray.length == 0 ) ) return -1 ; boolean found = false ; for ( int i = 0 ; i < strArray.length ; i++ ) { if ( strArray[i] == null ) { if ( searchStr == null ) found = true ; } else { if ( ignoreCase ) found = strArray[i].equalsIgnoreCase( searchStr ) ; else found = strArray[i].equals( searchStr ) ; } if ( found ) return i ; } return -1 ; } // indexOfString() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes before the * first occurance of the specified separator. * If the string starts with a separator, the result will be an empty string. * If the string doesn't contain the separator the method returns null or * the whole string, depending on the returnNull flag. * * @param str The string of which the prefix is desired * @param separator Separates the prefix from the rest of the string * @param returnNull Specifies if null will be returned if no separator is found */ protected String prefix( String str, String separator, boolean returnNull ) { if ( str == null ) return null ; if ( separator == null ) return ( returnNull ? null : str ) ; int index = str.indexOf( separator ) ; if ( index >= 0 ) return str.substring( 0, index ) ; else return ( returnNull ? null : str ) ; } // prefix() // ------------------------------------------------------------------------- /** * Returns the substring of the given string that comes after the * first occurance of the specified separator. * If the string ends with a separator, the result will be an empty string. * If the string doesn't contain the separator the method returns null or * the whole string, depending on the returnNull flag. * * @param str The string of which the suffix is desired * @param separator Separates the suffix from the rest of the string * @param returnNull Specifies if null will be returned if no separator is found */ protected String suffix( String str, String separator, boolean returnNull ) { if ( str == null ) return null ; if ( separator == null ) return ( returnNull ? null : str ) ; int index = str.indexOf( separator ) ; if ( index >= 0 ) return str.substring( index + separator.length() ) ; else return ( returnNull ? null : str ) ; } // suffix() // ------------------------------------------------------------------------- /** * Removes the given strings from the array. * If removeStrings is null it means that all null values are removed from * the first array. */ protected String[] removeFromStringArray( String[] strings, String[] removeStrings ) { List list ; boolean remains ; list = new ArrayList( strings.length ) ; for (int i = 0; i < strings.length; i++) { if ( removeStrings == null ) { remains = strings[i] != null ; } else { remains = ! this.contains( removeStrings, strings[i] ) ; } if ( remains ) { list.add( strings[i] ) ; } } return (String[])list.toArray( new String[list.size()] ) ; } // removeFromStringArray() // ------------------------------------------------------------------------- } // class StringUtil