/*
* © Copyright IBM Corp. 2012-2013
*
* 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 com.ibm.commons.util;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Platform;
/**
* <P>This class contains helpers for string manipulation.</P>
*
* @ibm-api
*/
public class StringUtil {
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final String SPACE = " ";
public static final String EMPTY_STRING = "";
/**
* Unit test.
* @param args
*/
// public static void main(String args[]) {
// testExpandProperties(args);
// testMnemonics(args);
// }
// public static void testMnemonics(String args[]) {
// String a = "hi&"; // $NON-NLS-1$
// String b= "&&hello"; // $NON-NLS-1$
// String c = "&";
// String d = "whats up (&&):"; // $NON-NLS-1$
// String f = "(&a)"; // $NON-NLS-1$
// String e = "(&b"; // $NON-NLS-1$
// String g = "&d"; // $NON-NLS-1$
// String h = "hi &there"; // $NON-NLS-1$
//
// testMnemonics(a, "hi&"); // $NON-NLS-1$
// testMnemonics(b, "&hello"); // $NON-NLS-1$
// testMnemonics(c, "&");
// testMnemonics(d, "whats up :"); // $NON-NLS-1$
// testMnemonics(f, "");
// testMnemonics(e, "(b"); // $NON-NLS-1$
// testMnemonics(g, "d");
// testMnemonics(h, "hi there"); // $NON-NLS-1$
// }
// private static void testMnemonics(String test, String correct) {
// String removed = removeMnemonics(test);
// if (!StringUtil.equals(removed, correct)) {
// System.out.println("Failed:" + test + " removed was:" + removed + " instead of:" + correct); // $NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$
// }
// }
// public static void testExpandProperties(String args[]) {
// testExpandProperties(""); // $NON-NLS-1$
// testExpandProperties("a"); // $NON-NLS-1$
// testExpandProperties("aaa"); // $NON-NLS-1$
// testExpandProperties("${java.home}"); // $NON-NLS-1$
// testExpandProperties("a${java.home}"); // $NON-NLS-1$
// testExpandProperties("${java.home}a"); // $NON-NLS-1$
// testExpandProperties("aa${java.home}aa"); // $NON-NLS-1$
// testExpandProperties("${java.home}${java.home}"); // $NON-NLS-1$
// testExpandProperties("aa${java.home}${java.home}aa"); // $NON-NLS-1$
// testExpandProperties("aa${java.home}aa${java.home}aa"); // $NON-NLS-1$
// testExpandProperties("${java.home}aa${java.home}"); // $NON-NLS-1$
// }
// public static void testExpandProperties(String exp) {
// String s = expandProperties(exp);
// System.out.println(exp+"="+s);
// }
/**
* Test the string equality, ignoring the case.
* The 2 parameters can be null as far they are assimiled as empty.
* @param s1 the first string to compare
* @param s2 the first string to compare
* @return true if the 2 strings are equals, false otherwise
* @ibm-api
*/
public static final boolean equalsIgnoreCase( String s1, String s2 ) {
if( s1==null || s2==null ) {
return isEmpty(s1)==isEmpty(s2);
}
return s1.equalsIgnoreCase(s2);
}
/**
* Concat a list of strings into a single string.
* @param strings the array of strings used
* @param sep the separator between strings
* @param trim indicate if the strings must be trimmed
* @return the concatened string
* @ibm-api
*/
public static String concatStrings( String[] strings, char sep, boolean trim ) {
int count = strings.length;
if( count==0 ) {
return ""; //$NON-NLS-1$
}
if( count==1 ) {
return trim ? trim(strings[0]) : strings[0];
}
StringBuilder b = new StringBuilder();
for( int i=0; i<count; i++ ) {
if( i>0 ) {
b.append(sep);
}
b.append( trim ? trim(strings[i]) : strings[i] );
}
return b.toString();
}
/**
* Trims the space characters from both ends of a string.
* All characters that have codes less than or equal to
* <code>'\u0020'</code> (the space character) are considered to be
* white space.
* @param s the string to edit
* @return the trimmed string
* @ibm-api
*/
public static final String trim(String s) {
// Call the String method which more efficient
if (s!=null) {
return s.trim();
} else {
return null;
}
}
/**
* Trims the spaces characters from both ends of of the character array.
* @param array the char array to trim
* @return the trimmed string
* @ibm-api
*/
public static final String trim( char[] array ) {
int count = array.length;
int last = count;
int st = 0;
while ((st < last) && isSpace(array[st])) {
st++;
}
while ((st < last) && isSpace(array[last - 1])) {
last--;
}
if( last>st ) {
return new String( array, st, last-st );
}
return ""; //$NON-NLS-1$
}
/**
* Compares two strings.
* The comparison is based on the Unicode value of each character in
* the strings.
* @param s1 the first string
* @param s2 the second string
* @return the value <code>0</code> if s1 is equal to s2. A value less than
* <code>0</code> if s1<s2 and a value greater than <code>0</code>
* if s1>s2.
* @ibm-api
*/
public static int compareTo(String s1, String s2) {
boolean e1 = isEmpty(s1);
boolean e2 = isEmpty(s2);
if( e1 || e2 ) {
if( e1 && !e2 ) return -1;
if( !e1 && e2 ) return 1;
return 0;
}
return s1.compareTo(s2);
}
/**
* Compares two strings ignoring the case.
* The comparison is based on the Unicode value of each character in
* the strings. When sun will provide such a native String function, it will
* be more optimized.
* @param s1 the first string
* @param s2 the second string
* @return the value <code>0</code> if s1 is equal to s2. A value less than
* <code>0</code> if s1<s2 and a value greater than <code>0</code>
* if s1>s2.
* @ibm-api
*/
public static int compareToIgnoreCase(String s1, String s2) {
boolean e1 = isEmpty(s1);
boolean e2 = isEmpty(s2);
if( e1 || e2 ) {
if( e1 && !e2 ) return -1;
if( !e1 && e2 ) return 1;
return 0;
}
return s1.compareToIgnoreCase(s2);
}
/**
* Test the string equality.
* The 2 parameters can be null as far they are assimiled as empty.
* @param s1 the first string to compare
* @param s2 the first string to compare
* @return true if the 2 strings are equals, false otherwise
* @ibm-api
*/
public static final boolean equals( String s1, String s2 ) {
if( s1==null || s2==null ) {
return isEmpty(s1)==isEmpty(s2);
}
return s1.equals(s2);
}
/**
* Test if the specified objects are equal.
* This method acts as Object.equals except that it checks for nullity.
* @param str1 the first object to test
* @param str2 the second object to test
* @return true if the 2 objects are equals, false otherwise
* @ibm-api
*/
static public boolean equals(Object str1, Object str2) {
if (str1 == null && str2 == null)
return true;
if (str1 != null)
return str1.equals(str2);
if (str2 != null)
return str2.equals(str1);
return false;
}
/**
* Test if a string is empty.
* A string is considered empty if it is either null or has a length of 0 characters.
* @param s the string to check
* @return true if the string is empty
* @ibm-api
*/
public static boolean isEmpty(String s) {
return s==null || s.length()==0;
}
/**
* Test if a string is not empty.
* A string is considered empty if it is either null or has a length of 0 characters.
* @param s the string to check
* @return true if the string is not empty
* @ibm-api
*/
public static boolean isNotEmpty(String s) {
return s!=null && s.length()>0;
}
/**
* Return a non-null string if this string is null
* @ibm-api
*/
public static String getNonNullString(String string) {
return string == null ? "" : string;//$NON-NLS-1$
}
/**
* Test if a string is only made of spaces.
* By spaces, we mean blank, tab, CR and LF.
* @param s the string to check
* @return true if the string is only made of spaces (or if it is empty)
* @ibm-api
*/
public static final boolean isSpace( String s ) {
if( s!=null ) {
int len = s.length();
for( int i=0; i<len; i++ ) {
char c = s.charAt(i);
if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) {
return false;
}
}
}
return true;
}
/**
* Format a string.
* Format a string using a formt string and parameters. Each entry like {n} in the format string
* is replaced by the actual parameter value converted to a string.
* @param fmt the format string
* @param p1 the first message parameter
* @param p2 the second message parameter
* @param p3 the third message parameter
* @param p4 the fourth message parameter
* @param p5 the fifth message parameter
* @param p6 the sixth message parameter
* @return the formatted string
* @ibm-api
*/
public static final String format( String fmt, Object... parameters) {
if( fmt!=null ) {
FastStringBuffer buffer = new FastStringBuffer();
return buffer.appendFormat( fmt, parameters ).toString();
}
return ""; //$NON-NLS-1$
}
/**
* Convert an object to a string.
* The resulting string is limited to 32 characters.
* @param o the object to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( Object o ) {
return toString(o,32);
}
/**
* Convert a character to a string.
* @param ch the character to convert
* @return the resulting string
* @ibm-api
*/
public static String toString(char ch) {
// Optimize that for 1.4?
char[] array = new char[] {ch};
return new String(array);
}
/**
* Convert a byte to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( byte value ) {
return Byte.toString(value);
}
/**
* Convert a short to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( short value ) {
return Short.toString(value);
}
/**
* Convert an integer to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( int value ) {
return Integer.toString(value);
}
/**
* Convert a long to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( long value ) {
return Long.toString(value);
}
/**
* Convert a float to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( float value ) {
return Float.toString(value);
}
/**
* Convert a double to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( double value ) {
return Double.toString(value);
}
/**
* Convert a boolean to a string.
* @param value the value to convert
* @return the resulting string
* @ibm-api
*/
public static String toString( boolean value ) {
return value ? "true" : "false"; // $NON-NLS-1$ $NON-NLS-2$
}
/**
* Convert a object to its string representation.
* This function takes care of null objects.
* @param value the value to be converted
* @return the string representing the object
* @ibm-api
*/
public static final String toString( Object value, int max ) {
if( value!=null ) {
if( value.getClass().isArray() ) {
return toStringArray(value,-1,max);
} else {
// Simply convert the object
return value.toString();
}
}
return ""; //$NON-NLS-1$
}
/**
* Convert a integer to its string representation and fill with characters
* on left to match the number of digits required.
* If the number cannot fit in the specified digits, then the return string
* is only composed of '*'.
* @param value the value to be converted
* @param digits the number of desired digits
* @param fill the character used to fill
* @return the string representing the integer
* @ibm-api
*/
public static final String toString( int value, int digits, char fill ) {
FastStringBuffer b = new FastStringBuffer();
String s = Integer.toString( value );
if( s.length()<=digits ) {
b.repeat( fill, digits-s.length() );
b.append(s);
} else {
b.repeat( '*', digits );
}
return b.toString();
}
/**
* Converts a collection full of Strings to a string array.
* @ibm-api
*/
public static String[] toStringArray(Collection strings) {
if( null == strings || strings.size() == 0 )
return StringUtil.EMPTY_STRING_ARRAY;
return (String[])strings.toArray(new String[strings.size()]);
}
/**
* @ibm-not-published
*/
public static final String toStringArray( Object value, int used, int max ) {
int nItem = -1;
boolean[] za = null; char[] ca = null; byte[] ba = null;
short[] sa = null; int[] ia = null; long[] la = null;
float[] fa = null; double[] da = null; Object[] oa = null;
// Find the good array type
if( value instanceof boolean[] )
{ za = (boolean[])value; nItem = za.length; }
else if( value instanceof char[] )
{ ca = (char[])value; nItem = ca.length; }
else if( value instanceof byte[] )
{ ba = (byte[])value; nItem = ba.length; }
else if( value instanceof short[] )
{ sa = (short[])value; nItem = sa.length; }
else if( value instanceof int[] )
{ ia = (int[])value; nItem = ia.length; }
else if( value instanceof long[] )
{ la = (long[])value; nItem = la.length; }
else if( value instanceof float[] )
{ fa = (float[])value; nItem = fa.length; }
else if( value instanceof double[] )
{ da = (double[])value; nItem = da.length; }
else if( value instanceof Object[] )
{ oa = (Object[])value; nItem = oa.length; }
if( used>=0 ) {
nItem = used;
}
// And browse the array
if( nItem>=0 ) {
StringBuilder buf = new StringBuilder(512);
buf.append( Integer.toString(nItem) );
buf.append( " {" ); //$NON-NLS-1$
int count = max<nItem ? max : nItem;
for( int i=0; i<count; i++ ) {
if( i!=0 ) buf.append( ", " ); //$NON-NLS-1$
if( za!=null ) {
buf.append( toString(za[i]) );
} else if( ca!=null ) {
buf.append( '\'' );
buf.append( ca[i] );
buf.append( '\'' );
} else if( ba!=null ) {
buf.append( toString(ba[i]) );
} else if( sa!=null ) {
buf.append( toString(sa[i]) );
} else if( ia!=null ) {
buf.append( toString(ia[i]) );
} else if( la!=null ) {
buf.append( toString(la[i]) );
} else if( fa!=null ) {
buf.append( toString(fa[i]) );
} else if( da!=null ) {
buf.append( toString(da[i]) );
} else if( oa!=null ) {
buf.append( toString(oa[i]) );
}
}
if( max<nItem ) buf.append( ", ..." ); //$NON-NLS-1$
buf.append( "}" ); //$NON-NLS-1$
return buf.toString();
} else {
return format( "Unknown java array type {0}", value.getClass().toString() ); // $NON-NLS-1$
}
}
/**
* Create a new string by repeating a character.
* @param toRepeat the character to repeat
* @param count the number of repetition
* @return the resulting string
* @ibm-api
*/
public static final String repeat( char toRepeat, int count ) {
StringBuilder b = new StringBuilder(count);
for( int i=0; i<count; i++ ) {
b.append( toRepeat );
}
return b.toString();
}
/**
* Create a new string by repeating a string.
* @param toRepeat the string to repeat
* @param count the number of repetition
* @return the resulting string
* @ibm-api
*/
public static final String repeat( String toRepeat, int count ) {
StringBuilder b = new StringBuilder(count*toRepeat.length());
for( int i=0; i<count; i++ ) {
b.append( toRepeat );
}
return b.toString();
}
/**
* Replace the first occurrence of a string within a source string.
* @param source the source string
* @param value the string to search for
* @param replace the string replacement
* @return the resulting string
* @ibm-api
*/
public static final String replaceFirst( String source, String value, String replace ) {
if( StringUtil.isEmpty(source) || StringUtil.isEmpty(value) ) {
return ""; //$NON-NLS-1$
}
if(replace==null ) {
replace = ""; //$NON-NLS-1$
}
int idx = source.indexOf(value);
if( idx>=0 ) {
// Initialize the buffer with the begining of the string
FastStringBuffer buffer = new FastStringBuffer();
buffer.append( source, 0, idx );
// Append the change to the str
buffer.append(replace);
int next = idx+value.length();
// Append the string up to the next occurence of the value
buffer.append( source, next, source.length() );
return buffer.toString();
}
// Nothing changed in the string
return source;
}
/**
* Replace all the occurrences of a string within a source string.
* @param source the source string
* @param value the string to search for
* @param replace the string replacement
* @return the resulting string
* @ibm-api
*/
public static final String replace( String source, String value, String replace ) {
if( isEmpty(source) || isEmpty(value) ) {
return ""; //$NON-NLS-1$
}
if(replace==null ) {
replace = ""; //$NON-NLS-1$
}
int idx = source.indexOf(value);
if( idx>=0 ) {
// Initialize the buffer with the begining of the string
FastStringBuffer buffer = new FastStringBuffer();
buffer.append( source, 0, idx );
int next;
do {
// Append the change to the str
buffer.append(replace);
next = idx+value.length();
// And search for the next occurence
idx = source.indexOf(value,next);
// Append the string up to the next occurence of the value
buffer.append( source, next, idx>=0 ? idx : source.length() );
} while(idx>=0);
return buffer.toString();
}
// Nothing changed in the string
return source;
}
/**
* Replace all the occurrences of a character within a source string.
* @param source the source string
* @param value the character to search for
* @param replace the character replacement
* @return the resulting string
* @ibm-api
*/
public static final String replace( String string, char value, char replace ) {
int idx = string.indexOf(value);
if( idx>=0 ) {
// Initialize the buffer with the begining of the string
FastStringBuffer buffer = new FastStringBuffer();
buffer.append( string, 0, idx );
int next;
do {
// Append the change to the str
if( replace!=0 ) {
buffer.append(replace);
}
next = idx+1;
// And search for the next occurence
idx = string.indexOf(value,next);
// Append the string up to the next occurence of the value
buffer.append( string, next, idx>=0 ? idx : string.length() );
} while(idx>=0);
return buffer.toString();
}
// Nothing change in the string
return string;
}
/**
* Convert an integer to an Hexa string and pad the result with '0'
* @param value the int to convert
* @param nChars the number of characters of the result
* @return the resulting string
* @ibm-api
* @throws NumberFormatException if nChars is less that the actual number of characters needed
*/
public static final String toUnsignedHex( int value, int nChars ) {
FastStringBuffer b = new FastStringBuffer();
//String s = Integer.toHexString(value);
for( int i=7; i>=0; i-- ) {
int v = (value >>> (i*4)) & 0x0F;
if( b.length()>0 || v!=0 || i<nChars || i==0 ) {
b.append(hexChar(v));
}
}
if( nChars>0 && b.length()>nChars ) {
throw new NumberFormatException(
StringUtil.format( "Hexadecimal number {0} too big to fit in '{1}' characters", //$NLS-StringUtil.StringUtil.HexNumTooBig.Exception-1$
StringUtil.toString(value),
StringUtil.toString(nChars) ));
}
return b.toString();
}
public static final char hexChar(int v) {
return (char)((v>=10) ? (v-10+'A') : (v+'0'));
}
public static final int hexValue(char c) {
if( c>='0' && c<='9' ) {
return c-'0';
}
if( c>='A' && c<='F' ) {
return c-'A'+10;
}
if( c>='a' && c<='f' ) {
return c-'a'+10;
}
// Do not throw an exception...
return -1;
}
/**
* Breaks a string into an array of substrings, with the delimeter removed.
* The delimeter character passed as aparanmeter. Note that
* <CODE>java.util.StringTokenizer</CODE> offers similar functionality.
* This method differs by the fact that it returns all of the tokens at once,
* using a String array, and does not require the explicit creation of a tokenizer
* object. This function also returns empty strings when delimiters are concatened,
* which is not the case of <CODE>java.util.StringTokenizer</CODE>. Finally,
* the delimiter is unique and passed as a char, which makes the method much faster.<BR>
* @param s the string to split
* @param c the delimeter
* @param trim indicates if the strings returned should be trimmed
* @return the substrings of s
* @ibm-api
*/
public static String[] splitString( String s, char sep, boolean trim ) {
if( s==null ) {
return EMPTY_STRING_ARRAY;
}
return splitString( null, 0, s, 0, sep, trim );
}
private static String[] splitString( String[] result, int count, String s, int pos, char sep, boolean trim ) {
int newPos = s.indexOf(sep,pos);
if( newPos>=0 ) {
result = splitString( null, count+1, s, newPos+1, sep, trim );
result[count] = s.substring( pos, newPos );
} else {
result = new String[count+1];
result[count] = s.substring( pos );
}
if(trim) {
result[count] = result[count].trim();
}
return result;
}
public static String[] splitString( String s, String sep, boolean trim ) {
if( s==null ) {
return EMPTY_STRING_ARRAY;
}
if( isEmpty(sep) ){
// Handling this like the JavaScript split method,
// if the separator is omitted, the entire string is returned.
// Different to the Java String split method, which returns
// an array full with entries for each character.
return new String[]{s};
}
return splitString( null, 0, s, 0, sep, trim );
}
private static String[] splitString( String[] result, int count, String s, int pos, String sep, boolean trim ) {
int newPos = s.indexOf(sep,pos);
if( newPos>=0 ) {
result = splitString( null, count+1, s, newPos+sep.length(), sep, trim );
result[count] = s.substring( pos, newPos );
} else {
result = new String[count+1];
result[count] = s.substring( pos );
}
if(trim) {
result[count] = result[count].trim();
}
return result;
}
/**
* Breaks a string into an array of substrings, with the delimeter removed.
* The delimeter character passed as aparanmeter. Note that
* <CODE>java.util.StringTokenizer</CODE> offers similar functionality.
* This method differs by the fact that it returns all of the tokens at once,
* using a String array, and does not require the explicit creation of a tokenizer
* object. This function also returns empty strings when delimiters are concatened,
* which is not the case of <CODE>java.util.StringTokenizer</CODE>. Finally,
* the delimiter is unique and passed as a char, which makes the method much faster.<BR>
* The returned strings are *not* trimmed.
* @param s the string to split
* @param c the delimeter
* @return the substrings of s
* @ibm-api
*/
public static final String[] splitString(String s, char sep) {
return splitString(s,sep,false);
}
/**
* Trims the space characters from the beginning of a string.
* For example, the call <CODE>ltrim (" Tennessee")</CODE>
* returns the string "Tennessee".<BR>
* @param s the string to edit
* @return the trimmed string
* @ibm-api
*/
public static final String ltrim(String s) {
int count = s.length();
int st = 0;
while ((st < count) && isSpace(s.charAt(st))) {
st++;
}
return st>0 ? s.substring( st, count ) : s;
}
private static boolean isSpace( char c ) {
return c <= ' ';
}
/**
* Trims the space characters from the end of a string.
* For example, the call <CODE>rtrim ("Tennessee ")</CODE>
* returns the string "Tenness".<BR>
* All characters that have codes less than or equal to
* <code>'\u0020'</code> (the space character) are considered to be
* white space.
* @param s the string to edit
* @return the trimmed string
* @ibm-api
*/
public static final String rtrim(String s) {
int count = s.length();
int len = count;
while ((0 < len) && isSpace(s.charAt(len-1)) ) {
len--;
}
return (len < count) ? s.substring(0, len) : s;
}
/**
* Returns the index within this string of the first occurrence of the
* specified string.
* The search is done ignore the character case.
* @param source the string to search
* @param str the string to search for
* @param fromIndex the index to start from
* @return the index of the first occurrence of the string in the
* character sequence represented by this object, or
* <code>-1</code> if the string does not occur.
* @ibm-api
*/
public static int indexOfIgnoreCase(String source, String str, int fromIndex) {
int count = source.length();
int strCount = str.length();
int max = count - strCount;
if (fromIndex >= count) {
if (count == 0 && fromIndex == 0 && strCount == 0) {
/* There is an empty string at index 0 in an empty string. */
return 0;
}
/* Note: fromIndex might be near -1>>>1 */
return -1;
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (str.length() == 0) {
return fromIndex;
}
char first = Character.toLowerCase(str.charAt(0));
int i = fromIndex;
startSearchForFirstChar:
while (true) {
/* Look for first character. */
while (i <= max && Character.toLowerCase(source.charAt(i)) != first) {
i++;
}
if (i > max) {
return -1;
}
/* Found first character, now look at the rest of v2 */
int j = i + 1;
int end = j + strCount - 1;
int k = 1;
while (j < end) {
if (Character.toLowerCase(source.charAt(j++)) != Character.toLowerCase(str.charAt(k++))) {
i++;
/* Look for str's first char again. */
continue startSearchForFirstChar;
}
}
return i; /* Found whole string. */
}
}
/**
* Returns the index within this string of the first occurrence of the
* specified string.
* The search is done ignore the character case.
* @param source the string to search
* @param str the string to search for
* @return the index of the first occurrence of the string in the
* character sequence represented by this object, or
* <code>-1</code> if the string does not occur.
* @ibm-api
*/
public static int indexOfIgnoreCase(String source, String str) {
return indexOfIgnoreCase(source, str, 0);
}
/**
* Returns the index within this string of the last occurrence of the
* specified string.
* The search is done ignore the character case.
* @param source the string to search
* @param str the string to search for
* @param fromIndex the index to start from
* @return the index of the first occurrence of the string in the
* character sequence represented by this object, or
* <code>-1</code> if the string does not occur.
* @ibm-api
*/
public static int lastIndexOfIgnoreCase(String source, String str, int fromIndex) {
int count = source.length();
int strCount = str.length();
/*
* Check arguments; return immediately where possible. For
* consistency, don't check for null str.
*/
int rightIndex = count - strCount;
if (fromIndex < 0) {
return -1;
}
if (fromIndex > rightIndex) {
fromIndex = rightIndex;
}
/* Empty string always matches. */
if (strCount == 0) {
return fromIndex;
}
int strLastIndex = strCount - 1;
char strLastChar = Character.toLowerCase(str.charAt(strLastIndex));
int min = strCount - 1;
int i = min + fromIndex;
startSearchForLastChar:
while (true) {
/* Look for the last character */
while (i >= min && Character.toLowerCase(source.charAt(i)) != strLastChar) {
i--;
}
if (i < min) {
return -1;
}
/* Found last character, now look at the rest of v2. */
int j = i - 1;
int start = j - (strCount - 1);
int k = strLastIndex - 1;
while (j > start) {
if (Character.toLowerCase(source.charAt(j--)) != Character.toLowerCase(str.charAt(k--)) ) {
i--;
/* Look for str's last char again. */
continue startSearchForLastChar;
}
}
return start + 1; /* Found whole string. */
}
}
/**
* Returns the index within this string of the last occurrence of the
* specified string.
* The search is done ignore the character case.
* @param source the string to search
* @param str the string to search for
* @return the index of the first occurrence of the string in the
* character sequence represented by this object, or
* <code>-1</code> if the string does not occur.
* @ibm-api
*/
public static int lastIndexOfIgnoreCase(String source, String str) {
return lastIndexOfIgnoreCase(source, str, source.length());
}
/**
* Identical to String.startsWith but case insensitive.
* @ibm-api
*/
public static boolean startsWithIgnoreCase(String s, String prefix) {
return startsWithIgnoreCase(s,prefix, 0);
}
/**
* Identical to String.startsWith but case insensitive.
* @ibm-api
*/
public static boolean startsWithIgnoreCase(String s, String prefix, int start) {
return s.regionMatches(true, start, prefix, 0, prefix.length());
}
/**
* Identical to String.endsWith but case insensitive.
* @ibm-api
*/
public static boolean endsWithIgnoreCase(String s, String suffix) {
return s.regionMatches(true, s.length() - suffix.length(), suffix, 0, suffix.length());
}
//========================================================================================
// Basic password encryption
//========================================================================================
private static int MINPWDLENGTH = 16;
private static int[] ENCRYPTION = new int[] { 187, 89, 189, 17, 45, 3, 0, 98, 79, 232, 65, 98, 75, 3, 224, 177 };
/**
* @ibm-not-published
* @deprecated
*/
public static boolean isEncrypted( String pwd ) {
if (pwd==null) {
return false;
}
return pwd.startsWith("[") && pwd.endsWith("]"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @ibm-not-published
* @deprecated
*/
public static String encrypt( String pwd ) {
return encrypt(pwd,null);
}
/**
* @ibm-not-published
* @deprecated
*/
public static String encrypt( String pwd, String ctx ) {
if (pwd==null) {
return null;
}
int offset;
if(StringUtil.isNotEmpty(ctx)) {
int acc = Math.abs((int)(ctx.hashCode() % ENCRYPTION.length));
offset = Math.min(ENCRYPTION.length, acc );
} else {
offset = Math.min(ENCRYPTION.length, (int)(Math.random()*ENCRYPTION.length) );
}
FastStringBuffer b = new FastStringBuffer();
b.append( '[' );
// Write the offset/count
encryptChar( b, 0, (char)offset );
encryptChar( b, offset++, (char)(pwd.length()) );
for( int i=0; i<Math.max(MINPWDLENGTH,pwd.length()); i++ ) {
char c;
if(i<pwd.length()) {
c = pwd.charAt(i);
} else {
if(StringUtil.isNotEmpty(ctx)) {
int pwdlen = pwd.length();
c = ctx.charAt((i-pwdlen)%ctx.length());
} else {
c = (char)(Math.random()*64+32);
}
}
encryptChar( b, offset++, c );
}
b.append( ']' );
return b.toString();
}
/**
* @ibm-not-published
* @deprecated
*/
public static String decrypt( String pwd ) {
if( isEncrypted(pwd) ) {
FastStringBuffer b = new FastStringBuffer();
// Read the offset/count;
int offset = decryptChar(pwd,0,1);
int pwdlength = decryptChar(pwd,offset++,3);
for( int i=0; i<pwdlength; i++ ) {
b.append(decryptChar(pwd,offset++,5+i*2));
}
return b.toString();
}
return pwd;
}
private static void encryptChar( FastStringBuffer b, int offset, char c ) {
int xor = ENCRYPTION[offset%ENCRYPTION.length];
int val = ((int)c) ^ xor;
char c1 = (char)((val&0x00F0)/16+(int)'A');
char c2 = (char)((val&0x000F)+(int)'A');
b.append(c1);
b.append(c2);
}
private static char decryptChar( String pwd, int offset, int pos ) {
int xor = ENCRYPTION[offset%ENCRYPTION.length];
char c1 = pwd.charAt(pos);
char c2 = pwd.charAt(pos+1);
char c = (char)(((c1-(int)'A')*16 + (c2-(int)'A')) ^ xor);
return c;
}
/**
* Converts an HTML string to a Java one, converting the numeric entities
* (Ӓ) sent by the browser.
* this does not handle HTML strings, just XML strings. i.e. is
* handled but is not.
* @param s the HTML string
* @return the converted string
* @ibm-api
*/
public static String fromXmlInputString(String s) {
if (isEmpty(s)) {
return s;
}
int l=s.length();
FastStringBuffer b = null;
try {
int start=0;
int firstChar;
while ((firstChar=s.indexOf("", start))!=-1) { //$NON-NLS-1$
boolean ok=false;
int lastChar=firstChar+2;
for (;;) {
if (lastChar>=l) {
break;
}
char c=s.charAt(lastChar);
if (c==';') {
ok=true;
break;
}
if (c<'0' || c>'9') {
break;
}
lastChar++;
}
if (ok) {
int n=Integer.parseInt(s.substring(firstChar+2, lastChar));
if (b==null) {
b = new FastStringBuffer();
b.append(s, 0, firstChar);
} else {
b.append(s, start, firstChar);
}
b.append((char)n);
start=lastChar+1;
} else {
start=firstChar+2;
}
}
if (b!=null && start<l) {
b.append(s, start, l);
}
return b!=null ? b.toString() : s;
} finally {
b = null;
}
}
private static final String TRUE_STRING = "true"; //$NON-NLS-1$
private static final String FALSE_STRING = "false"; //$NON-NLS-1$
public static boolean isTrueValue(String stringToTest) {
return TRUE_STRING.equalsIgnoreCase(stringToTest);
}
public static boolean isFalseValue(String stringToTest) {
return FALSE_STRING.equalsIgnoreCase(stringToTest);
}
/**
* Returns a string whose first letter is a Capital letter, and a space is
* inserted anywhere an upper case letter exists in the existing string.
* For instance, if the user passes in thisIsATest - the following will
* be returned:
* This Is A Test
* @param sample: String - The string that you want to convert to proper case.
* @return String
* @ibm-api
*/
public static String getProperCaseString(String sample) {
if(sample == null) {
return null;
}
char[] chars = sample.toCharArray();
StringBuffer buffer = new StringBuffer(sample.length());
if(chars != null && chars.length > 0) {
buffer.append(Character.toUpperCase(chars[0]));
for(int i = 1; i < chars.length; i++) {
if(Character.isUpperCase(chars[i])) {
buffer.append(SPACE);
chars[i] = Character.toLowerCase(chars[i]);
}
buffer.append(chars[i]);
}
}
return buffer.toString();
}
private static String[] lineSeparators;
@SuppressWarnings("unchecked") // $NON-NLS-1$
public static String[] getLineSeparators() {
Map separators = Platform.knownPlatformLineSeparators();
List sepList = new ArrayList(separators.values());
// make sure the biggest separators are first, this means
// we wont end up with too many spaces.
Collections.sort(sepList, new Comparator() {
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
int s1L = s1.length();
int s2L = s2.length();
if (s1L > s2L) {
return -1;
} else if (s1L < s2L) {
return 1;
} else {
return 0;
}
}
});
return (String[]) sepList.toArray(new String[sepList.size()]);
}
/**
* Remove line breaks.
*/
public static String removeLineBreaks(String s) {
if (lineSeparators == null) {
lineSeparators = getLineSeparators();
}
for (int i = 0; i < lineSeparators.length; i++) {
s = replace(s, lineSeparators[i], SPACE);
}
return s;
}
/**
* Strip extra spaces and html tags.
*/
public static String parseHtml(String s) {
// Quickly strip the extra spaces
if(StringUtil.isNotEmpty(s)) {
StringBuilder b = new StringBuilder();
boolean space = true;
int len = s.length();
for(int i=0; i<len; i++ ) {
char c = s.charAt(i);
if(c==' ' || c=='\t') {
if(!space) {
b.append(' ');
space = true;
}
} else if(c=='<') {
// Skip the HTML tags for now
while(i<len && c!='>') {
i++;
}
} else {
b.append(c);
if(c=='\n' || c=='\r') {
space = true;
} else {
space = false;
}
}
}
return b.toString();
}
return s;
}
public static String getAutoGenNameFromJavaName(String javaName) {
if(javaName == null){
return null;
}
int len = javaName.length();
StringBuffer returnString = new StringBuffer(len);
char[] chars = javaName.toCharArray();
char c;
//We do not want the name to start with a digit or contain characters outside the range
//a-z A-Z 0-9 and '_'
boolean leadingDigit = false;
for (int i = 0; i < len; i++) {
c = chars[i];
if((c >= 'A' && c <= 'z') || (c >= '0' && c <= '9' ) || c == '_'){
if (i == 0) {
if(Character.isLetter(c)){
returnString.append(Character.toUpperCase(c));
}else{
leadingDigit = true;
}
} else {
if(leadingDigit){
if(Character.isLetter(c)){
leadingDigit = false;
returnString.append(Character.toUpperCase(c));
}
}else{
returnString.append(c);
}
}
}
else {
leadingDigit = i == 0;
}
}
return returnString.toString();
}
public static char getMnemonicCharacter(String text) {
char ret = (char)-1;
if (text != null) {
int index = text.indexOf("&");
if (index != -1 && (index < (text.length() - 1))) {
ret = text.charAt(index + 1);
}
}
return ret;
}
/**
* Create a name with the _copy_x appended, where X is the next available number.
*/
public static String generateCopyName(String sourceName, String[] listOfNames) {
// create a new name with same name + copy_n
StringBuffer buffer = new StringBuffer(sourceName);
String copyString = "copy"; // $NLS-StringUtil.copy-1$
String separator = "_";
StringBuffer copySeparator = new StringBuffer(separator);
copySeparator.append(copyString);
copySeparator.append(separator);
String copySep = copySeparator.toString();
int index = sourceName.indexOf(copySep);
long num = 1;
if (index != -1) {
String substring = sourceName.substring(index + copySep.length());
if (StringUtil.isNotEmpty(substring)) {
try {
num = Long.parseLong(substring);
buffer.delete(index + copySep.length(), buffer.length());
} catch (NumberFormatException nfe) {
buffer.append(copySep);
}
}
} else {
buffer.append(copySep);
}
return getNextUniqueValue(buffer.toString(), num, listOfNames);
}
/**
* Given the current name, append a long until a unique is found, starting at the given
* starting num.
*/
public static String getNextUniqueValue(String name, long startingNum, String[] listOfNames) {
boolean valid = true;
for (int i = 0; i < Long.MAX_VALUE; i++) {
StringBuffer newBuffer = new StringBuffer(name);
newBuffer.append(startingNum);
String test = newBuffer.toString();
if (listOfNames != null) {
for (int x = 0; x < listOfNames.length; x++) {
String currName = listOfNames[x];
if (StringUtil.equals(currName, test)) {
valid = false;
}
}
}
if (!valid) {
valid = true;
startingNum++;
} else {
return test;
}
}
return name;
}
/**
* Remove the mnemonics from a string.
*
* @param string
* @return If no mnemonics are found, the string is returned as is.
* If mnemonics are found, a new string without the
* mnemonics is returned.
*/
public static String removeMnemonics(String string) {
if ( string == null || string.indexOf('&') == -1 ) {
return string;
}
int strLen = string.length();
StringBuffer sb = new StringBuffer( strLen );
int lastIndex = 0;
int iIndex = string.indexOf('&');
while (iIndex != -1) {
if (iIndex == strLen - 1) {
break;
}
int modifier = 1;
// whitney - fix korean, japanese, etc. when you have some characters and (&C):
if ((iIndex - 1) >= 0 && (iIndex + 2) < string.length()
&& string.charAt(iIndex - 1) == '(' && string.charAt(iIndex + 2) == ')') {
--iIndex;
modifier = 4;
} else if (string.charAt(iIndex + 1) == '&') {
++iIndex;
}
sb.append(string.substring(lastIndex, iIndex));
iIndex += modifier;
lastIndex = iIndex;
iIndex = string.indexOf('&', iIndex);
}
if (lastIndex < strLen) {
sb.append(string.substring(lastIndex, strLen));
}
return sb.toString();
}
/**
* A Helper function for conditionally calling removeMnemonics.
* Used in the case where the mnemonic is conditionally removed based
* on if the control is in a dialog or not.
*
* @param string
* @param remove - if true remove any mnemonics in the string, if false just
* return the string.
* @return
*/
public static String removeMnemonics(String string, boolean remove) {
return remove ? removeMnemonics(string) : string;
}
/**
* Transforms a String into a fixed-length digest.
* This is a one-way transformation, but with consistent return value.
*
*
* @param str the String to transform
* @return the digest in hexadecimal form
*/
public static String getDigest(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5"); //$NON-NLS-1$
md.update(str.getBytes("UTF-8")); //$NON-NLS-1$
byte[] digest = md.digest();
return toHexValue(digest);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
/**
* Converts a byte array to a hexadecimal String equivalent.
*/
public static String toHexValue(byte[] barr) {
FastStringBuffer sb = new FastStringBuffer(barr.length*2);
for(int i=0; i<barr.length; i++) {
int unsigned = barr[i] & 0xFF;
sb.append(getUpperDigitAsHex(unsigned));
sb.append(getLowerDigitAsHex(unsigned));
}
return sb.toString();
}
private static char getUpperDigitAsHex(int b) {
int val = b / 16;
return toHex(val);
}
private static char getLowerDigitAsHex(int b) {
int val = b % 16;
return toHex(val);
}
private static final char A = 'a' - 10;
private static char toHex(int n) {
if((0 <= n) && (n<=9)) {
return (char) ('0' + n);
} else if((10 <= n) && (n <= 15)) {
return (char) (A + n);
} else {
throw new IllegalArgumentException(""+n);
}
}
public static boolean contains(Object[] objects, Object toTest) {
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
if (equals(objects[i], toTest)) {
return true;
}
}
}
return false;
}
public static boolean isLineSeparator(String s) {
if(isNotEmpty(s)) {
String[] separators = getLineSeparators();
return isContainedWithin(s, separators);
}
return false;
}
/**
* Checks if an array of string is empty.
* <p>
* An array is empty if it is nul, or if it contains no elements.
* </p>
* @param arr
* @return
*/
public static boolean isEmpty(String[] arr) {
return arr == null || arr.length < 1;
}
/**
* Checks if an array of string is not empty.
* <p>
* An array is empty if it is nul, or if it contains no elements.
* </p>
* @param arr
* @return
*/
public static boolean isNotEmpty(String[] arr) {
return arr != null && arr.length > 0;
}
public static boolean isContainedWithin(String s, String[] container) {
if(isNotEmpty(s) && isNotEmpty(container)) {
for(int i = 0; i < container.length; i++) {
if(equals(s, container[i])) {
return true;
}
}
}
return false;
}
/**
* Property expander
* This function replaces all the occurences of ${propname} by the actual
* property value
* @param s
* @param flag
* @return
*/
public static String expandProperties(String s) {
if(isEmpty(s)) {
return s;
}
int index = s.indexOf("${", 0);
if(index<0) {
return s;
}
StringBuilder b = new StringBuilder();
if(index>0) {
b.append(s,0,index);
}
do {
int end = s.indexOf('}',index);
if(end<0) {
// Error: just ignore the macro...
return b.toString();
}
// replace the value
String propName = s.substring(index+2,end);
String propValue = System.getProperty(propName);
if(isNotEmpty(propValue)) {
b.append(propValue);
}
index = end+1;
// And find the next occurence
int pos = s.indexOf("${", index);
if(pos<0) {
b.append(s,index,s.length());
return b.toString();
}
if(pos>index) {
b.append(s,index,pos);
}
index = pos;
} while(true);
}
/**
* Counts occurance of character in a provided string
* @param source
* @param match
* @return
*/
public static int countMatch(String source, char match)
{
int count = 0;
if(isNotEmpty(source)){
for (int i=0; i < source.length(); i++) {
if(StringUtil.equals(source.charAt(i), match)) {
count++;
}
}
}
return count;
}
}