/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.core.designer.util;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.teiid.core.designer.CoreModelerPlugin;
import org.teiid.core.designer.TeiidDesignerRuntimeException;
/**
* This is a common place to put String utility methods.
*
* @since 8.0
*/
public final class CoreStringUtil {
public interface Constants {
char CARRIAGE_RETURN_CHAR = '\r';
char LINE_FEED_CHAR = '\n';
char NEW_LINE_CHAR = LINE_FEED_CHAR;
char SPACE_CHAR = ' ';
char DOT_CHAR = '.';
char TAB_CHAR = '\t';
char DQUOTE_CHAR = '"';
String CARRIAGE_RETURN = String.valueOf(CARRIAGE_RETURN_CHAR);
String EMPTY_STRING = ""; //$NON-NLS-1$
String DBL_SPACE = " "; //$NON-NLS-1$
String LINE_FEED = String.valueOf(LINE_FEED_CHAR);
String NEW_LINE = String.valueOf(NEW_LINE_CHAR);
String SPACE = String.valueOf(SPACE_CHAR);
String DOT = String.valueOf(DOT_CHAR);
String TAB = String.valueOf(TAB_CHAR);
String DQUOTE_STR = "\""; //$NON-NLS-1$
String DOT_STR = "."; //$NON-NLS-1$
String[] EMPTY_STRING_ARRAY = new String[0];
// all patterns below copied from Eclipse's PatternConstructor class.
final Pattern PATTERN_BACK_SLASH = Pattern.compile("\\\\"); //$NON-NLS-1$
final Pattern PATTERN_QUESTION = Pattern.compile("\\?"); //$NON-NLS-1$
final Pattern PATTERN_STAR = Pattern.compile("\\*"); //$NON-NLS-1$
}
/**
* The String "'"
*/
public static final String SINGLE_QUOTE = "'"; //$NON-NLS-1$
/**
* The name of the System property that specifies the string that should be used to separate lines. This property is a
* standard environment property that is usually set automatically.
*/
public static final String LINE_SEPARATOR_PROPERTY_NAME = "line.separator"; //$NON-NLS-1$
/**
* The String that should be used to separate lines; defaults to {@link Constants#NEW_LINE}
*/
public static final String LINE_SEPARATOR = System.getProperty(LINE_SEPARATOR_PROPERTY_NAME, Constants.NEW_LINE);
public static final Comparator CASE_INSENSITIVE_ORDER = String.CASE_INSENSITIVE_ORDER;
public static final Comparator CASE_SENSITIVE_ORDER = new Comparator() {
/**
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
* @since 4.2
*/
@Override
public int compare( Object o1,
Object o2 ) {
if (o1 == o2) {
return 0;
}
return ((String)o1).compareTo((String)o2);
}
};
public static String getLineSeparator() {
return LINE_SEPARATOR;
}
/**
* Utility to return a string enclosed in ''. Creation date: (12/2/99 12:05:10 PM)
*/
public static String enclosedInSingleQuotes( String aString ) {
StringBuffer sb = new StringBuffer();
sb.append(SINGLE_QUOTE);
sb.append(aString);
sb.append(SINGLE_QUOTE);
return sb.toString();
}
/**
* Join string pieces and separate with a delimiter. Similar to the perl function of the same name. If strings or delimiter
* are null, null is returned. Otherwise, at least an empty string will be returned.
*
* @see #split
* @param strings String pieces to join
* @param delimiter Delimiter to put between string pieces
* @return One merged string
*/
public static String join( List strings,
String delimiter ) {
if (strings == null || delimiter == null) {
return null;
}
StringBuffer str = new StringBuffer();
// This is the standard problem of not putting a delimiter after the last
// string piece but still handling the special cases. A typical way is to check every
// iteration if it is the last one and skip the delimiter - this is avoided by
// looping up to the last one, then appending just the last one.
// First we loop through all but the last one (if there are at least 2) and
// put the piece and a delimiter after it. An iterator is used to walk the list.
int most = strings.size() - 1;
if (strings.size() > 1) {
Iterator iter = strings.iterator();
for (int i = 0; i < most; i++) {
str.append(iter.next());
str.append(delimiter);
}
}
// If there is at least one element, put the last one on with no delimiter after.
if (strings.size() > 0) {
str.append(strings.get(most));
}
return str.toString();
}
/**
* Return a stringified version of the array.
*
* @param array the array
* @param delim the delimiter to use between array components
* @return the string form of the array
*/
public static String toString( final Object[] array,
final String delim ) {
if (array == null) {
return ""; //$NON-NLS-1$
}
if (array.length == 0) {
return "[]"; //$NON-NLS-1$
}
final StringBuffer sb = new StringBuffer();
sb.append('[');
for (int i = 0; i < array.length; ++i) {
if (i != 0) {
sb.append(delim);
}
sb.append(array[i]);
}
sb.append(']');
return sb.toString();
}
/**
* Return a stringified version of the array, using a ',' as a delimiter
*
* @param array the array
* @return the string form of the array
* @see #toString(Object[], String)
*/
public static String toString( final Object[] array ) {
return toString(array, ","); //$NON-NLS-1$
}
/**
* Split a string into pieces based on delimiters. Similar to the perl function of the same name. The delimiters are not
* included in the returned strings.
*
* @see #join
* @param str Full string
* @param splitter Characters to split on
* @return List of String pieces from full string
*/
public static List split( String str,
String splitter ) {
StringTokenizer tokens = new StringTokenizer(str, splitter);
ArrayList l = new ArrayList(tokens.countTokens());
while (tokens.hasMoreTokens()) {
l.add(tokens.nextToken());
}
return l;
}
/**
* Break a string into pieces based on matching the full delimiter string in the text. The delimiter is not included in the
* returned strings.
*
* @param target The text to break up.
* @param delimiter The sub-string which is used to break the target.
* @return List of String from the target.
*/
public static List splitOnEntireString( String target,
String delimiter ) {
ArrayList result = new ArrayList();
if (delimiter.length() > 0) {
int index = 0;
int indexOfNextMatch = target.indexOf(delimiter);
while (indexOfNextMatch > -1) {
result.add(target.substring(index, indexOfNextMatch));
index = indexOfNextMatch + delimiter.length();
indexOfNextMatch = target.indexOf(delimiter, index);
}
if (index <= target.length()) {
result.add(target.substring(index));
}
} else {
result.add(target);
}
return result;
}
/**
* Split a string into pieces based on delimiters preserving spaces in quoted substring as on element in the returned list.
* The delimiters are not included in the returned strings.
*
* @see #join
* @param str Full string
* @param splitter Characters to split on
* @return List of String pieces from full string
*/
public static List splitPreservingQuotedSubstring( String str,
String splitter ) {
ArrayList l = new ArrayList();
StringTokenizer tokens = new StringTokenizer(str, splitter);
StringBuffer token = new StringBuffer();
while (tokens.hasMoreTokens()) {
token.setLength(0);
token.append(tokens.nextToken());
if (token.charAt(0) == '"') {
token.deleteCharAt(0);
while (tokens.hasMoreTokens()) {
token.append(Constants.SPACE + tokens.nextToken());
if (token.charAt(token.length() - 1) == '"') {
token.deleteCharAt(token.length() - 1);
break;
}
}
}
l.add(token.toString().trim());
}
return l;
}
/*
* Replace a single occurrence of the search string with the replace string
* in the source string. If any of the strings is null or the search string
* is zero length, the source string is returned.
* @param source the source string whose contents will be altered
* @param search the string to search for in source
* @param replace the string to substitute for search if present
* @return source string with the *first* occurrence of the search string
* replaced with the replace string
*/
public static String replace( String source,
String search,
String replace ) {
if (source != null && search != null && search.length() > 0 && replace != null) {
int start = source.indexOf(search);
if (start > -1) {
return new StringBuffer(source).replace(start, start + search.length(), replace).toString();
}
}
return source;
}
/*
* Replace all occurrences of the search string with the replace string
* in the source string. If any of the strings is null or the search string
* is zero length, the source string is returned.
* @param source the source string whose contents will be altered
* @param search the string to search for in source
* @param replace the string to substitute for search if present
* @return source string with *all* occurrences of the search string
* replaced with the replace string
*/
public static String replaceAll( String source,
String search,
String replace ) {
if (source != null && search != null && search.length() > 0 && replace != null) {
int start = source.indexOf(search);
if (start > -1) {
StringBuffer newString = new StringBuffer(source);
replaceAll(newString, search, replace);
return newString.toString();
}
}
return source;
}
public static void replaceAll( StringBuffer source,
String search,
String replace ) {
if (source != null && search != null && search.length() > 0 && replace != null) {
int start = source.toString().indexOf(search);
while (start > -1) {
int end = start + search.length();
source.replace(start, end, replace);
start = source.toString().indexOf(search, start + replace.length());
}
}
}
/**
* Simple static method to tuncate Strings to given length.
*
* @param in the string that may need tuncating.
* @param len the lenght that the string should be truncated to.
* @return a new String containing chars with length <= len or <code>null</code> if input String is <code>null</code>.
*/
public static String truncString( String in,
int len ) {
String out = in;
if (in != null && len > 0 && in.length() > len) {
out = in.substring(0, len);
}
return out;
}
/**
* Simple utility method to wrap a string by inserting line separators creating multiple lines each with length no greater
* than the user specified maximum. The method parses the given string into tokens using a space delimiter then reassembling
* the tokens into the resulting string while inserting separators when required. If the number of characters in a single
* token is greater than the specified maximum, the token will not be split but instead the maximum will be exceeded.
*
* @param str the string that may need tuncating.
* @param maxCharPerLine the max number of characters per line
* @return a new String containing line separators or the original string if its length was less than the maximum.
*/
public static String wrap( String str,
int maxCharPerLine ) {
int strLength = str.length();
if (strLength > maxCharPerLine) {
StringBuffer sb = new StringBuffer(str.length() + (strLength / maxCharPerLine) + 1);
strLength = 0;
List tokens = CoreStringUtil.split(str, Constants.SPACE);
Iterator itr = tokens.iterator();
while (itr.hasNext()) {
String token = (String)itr.next();
if (strLength + token.length() > maxCharPerLine) {
// sb.append(getLineSeparator());
sb.append(Constants.NEW_LINE);
strLength = 0;
}
sb.append(token);
sb.append(Constants.SPACE);
strLength += token.length() + 1;
}
return sb.toString();
}
return str;
}
/**
* Return the tokens in a string in a list. This is particularly helpful if the tokens need to be processed in reverse order.
* In that case, a list iterator can be acquired from the list for reverse order traversal.
*
* @param str String to be tokenized
* @param delimiter Characters which are delimit tokens
* @return List of string tokens contained in the tokenized string
*/
public static List getTokens( String str,
String delimiter ) {
ArrayList l = new ArrayList();
StringTokenizer tokens = new StringTokenizer(str, delimiter);
while (tokens.hasMoreTokens()) {
l.add(tokens.nextToken());
}
return l;
}
/**
* Return the number of tokens in a string that are seperated by the delimiter.
*
* @param str String to be tokenized
* @param delimiter Characters which are delimit tokens
* @return Number of tokens seperated by the delimiter
*/
public static int getTokenCount( String str,
String delimiter ) {
StringTokenizer tokens = new StringTokenizer(str, delimiter);
return tokens.countTokens();
}
/**
* Return the number of occurrences of token string that occurs in input string. Note: token is case sensitive.
*
* @param input
* @param token
* @return int
*/
public static int occurrences( String input,
String token ) {
int num = 0;
int index = input.indexOf(token);
while (index >= 0) {
num++;
index = input.indexOf(token, index + 1);
}
return num;
}
/**
* Return the last token in the string.
*
* @param str String to be tokenized
* @param delimiter Characters which are delimit tokens
* @return the last token contained in the tokenized string
*/
public static String getLastToken( String str,
String delimiter ) {
if (str == null) {
return Constants.EMPTY_STRING;
}
int beginIndex = 0;
if (str.lastIndexOf(delimiter) > 0) {
beginIndex = str.lastIndexOf(delimiter) + 1;
}
return str.substring(beginIndex, str.length());
}
/**
* Return the first token in the string.
*
* @param str String to be tokenized
* @param delimiter Characters which are delimit tokens
* @return the first token contained in the tokenized string
*/
public static String getFirstToken( String str,
String delimiter ) {
if (str == null) {
return Constants.EMPTY_STRING;
}
int endIndex = str.indexOf(delimiter);
if (endIndex < 0) {
endIndex = str.length();
}
return str.substring(0, endIndex);
}
/**
* Compute a displayable form of the specified string. This algorithm attempts to create a string that contains words that
* begin with uppercase characters and that are separated by a single space. For example, the following are the outputs of
* some sample inputs: <li>"aName" is converted to "A Name"</li> <li>"Name" is converted to "Name"</li> <li>"NAME" is
* converted to "NAME"</li> <li>"theName" is converted to "The Name"</li> <li>"theBIGName" is converted to "The BIG Name"</li>
* <li>"the BIG Name" is converted to "The BIG Name"</li> <li>"the big Name" is converted to "The Big Name"</li> <li>"theBIG"
* is converted to "The BIG"</li> <li>"SQLIndex" is converted to "SQL Index"</li> <li>"SQLIndexT" is converted to
* "SQL Index T"</li> <li>"SQLIndex T" is converted to "SQL Index T"</li> <li>"SQLIndex t" is converted to "SQL Index T"</li>
*
* @param str String to be converted; may be null
* @return the displayable form of <code>str</code>, or an empty string if <code>str</code> is either null or zero-length;
* never null
*/
public static String computeDisplayableForm( String str ) {
return computeDisplayableForm(str, Constants.EMPTY_STRING);
}
/**
* Compute a displayable form of the specified string. This algorithm attempts to create a string that contains words that
* begin with uppercase characters and that are separated by a single space. For example, the following are the outputs of
* some sample inputs: <li>"aName" is converted to "A Name"</li> <li>"Name" is converted to "Name"</li> <li>"NAME" is
* converted to "NAME"</li> <li>"theName" is converted to "The Name"</li> <li>"theBIGName" is converted to "The BIG Name"</li>
* <li>"the BIG Name" is converted to "The BIG Name"</li> <li>"the big Name" is converted to "The Big Name"</li> <li>"theBIG"
* is converted to "The BIG"</li> <li>"SQLIndex" is converted to "SQL Index"</li> <li>"SQLIndexT" is converted to
* "SQL Index T"</li> <li>"SQLIndex T" is converted to "SQL Index T"</li> <li>"SQLIndex t" is converted to "SQL Index T"</li>
* <p>
* An exception is "MetaMatrix", which is always treated as a single word
* </p>
*
* @param str String to be converted; may be null
* @param defaultValue the default result if the input is either null or zero-length.
* @return the displayable form of <code>str</code>, or the default value if <code>str</code> is either null or zero-length.
*/
public static String computeDisplayableForm( String str,
String defaultValue ) {
if (str == null || str.length() == 0) {
return defaultValue;
}
StringBuffer newName = new StringBuffer(str);
boolean previousCharUppercase = false;
// If the first character is lowercase, replace it with the uppercase ...
char prevChar = newName.charAt(0);
if (Character.isLowerCase(prevChar)) {
newName.setCharAt(0, Character.toUpperCase(prevChar));
previousCharUppercase = true;
}
if (newName.length() > 1) {
char nextChar;
char currentChar;
boolean currentCharUppercase;
boolean nextCharUppercase;
for (int i = 1; i != newName.length(); ++i) {
prevChar = newName.charAt(i - 1);
currentChar = newName.charAt(i);
previousCharUppercase = Character.isUpperCase(prevChar);
currentCharUppercase = Character.isUpperCase(currentChar);
// In the case where we're not at the end of the string ...
if (i != newName.length() - 1) {
nextChar = newName.charAt(i + 1);
nextCharUppercase = Character.isUpperCase(nextChar);
} else {
nextCharUppercase = false;
nextChar = ' ';
}
// If the previous character is a space, capitalize the current character
if (prevChar == ' ') {
newName.setCharAt(i, Character.toUpperCase(currentChar));
// do nothing
}
// Otherwise, if the current character is already uppercase ...
else if (currentCharUppercase) {
// ... and the previous character is not uppercase, then insert
if (!previousCharUppercase) {
// ... and this is not the 'M' of 'MetaMatrix' ...
if (currentChar != 'M'
|| i < 4
|| (!newName.substring(i - 4).startsWith(CoreModelerPlugin.Util.getString("StringUtil.Displayable")))) { //$NON-NLS-1$
newName.insert(i, ' ');
++i; // skip, since we just move the character back one position
}
}
// ... and the previous character is uppercase ...
else {
// ... but the next character neither uppercase or a space ...
if (!nextCharUppercase && nextChar != ' ') {
newName.insert(i, ' ');
++i; // skip, since we just move the character back one position
}
}
}
}
}
return newName.toString();
}
/**
* @since 3.0
*/
public static String computeDisplayableFormOfConstant( final String text ) {
return computeDisplayableFormOfConstant(text, Constants.EMPTY_STRING);
}
/**
* @since 3.0
*/
public static String computeDisplayableFormOfConstant( final String text,
final String defaultValue ) {
if (text == null || text.length() == 0) {
return defaultValue;
}
final StringBuffer buf = new StringBuffer();
String token;
for (final StringTokenizer iter = new StringTokenizer(text, "_"); iter.hasMoreTokens();) { //$NON-NLS-1$
token = iter.nextToken().toLowerCase();
if (buf.length() > 0) {
buf.append(' ');
}
buf.append(Character.toUpperCase(token.charAt(0)));
buf.append(token.substring(1));
}
return buf.toString();
}
public static String computePluralForm( String str ) {
return computePluralForm(str, Constants.EMPTY_STRING);
}
public static String computePluralForm( String str,
String defaultValue ) {
if (str == null || str.length() == 0) {
return defaultValue;
}
String result = str;
if (result.endsWith("es")) { //$NON-NLS-1$
// do nothing
} else if (result.endsWith("ss") || //$NON-NLS-1$
result.endsWith("x") || //$NON-NLS-1$
result.endsWith("ch") || //$NON-NLS-1$
result.endsWith("sh")) { //$NON-NLS-1$
result = result + "es"; //$NON-NLS-1$
} else if (result.endsWith("y") && !( //$NON-NLS-1$
result.endsWith("ay") || //$NON-NLS-1$
result.endsWith("ey") || //$NON-NLS-1$
result.endsWith("iy") || //$NON-NLS-1$
result.endsWith("oy") || //$NON-NLS-1$
result.endsWith("uy") || //$NON-NLS-1$
result.equalsIgnoreCase("any"))) { //$NON-NLS-1$
result = result.substring(0, result.length() - 1) + "ies"; //$NON-NLS-1$
} else {
result += "s"; //$NON-NLS-1$
}
return result;
}
public static String getStackTrace( final Throwable t ) {
final ByteArrayOutputStream bas = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(bas);
t.printStackTrace(pw);
pw.close();
return bas.toString();
}
/**
* Returns whether the specified text represents a boolean value, i.e., whether it equals "true" or "false"
* (case-insensitive).
*
* @since 4.0
*/
public static boolean isBoolean( final String text ) {
return (Boolean.TRUE.toString().equalsIgnoreCase(text) || Boolean.FALSE.toString().equalsIgnoreCase(text));
}
/**
* <p>
* Returns whether the specified text is either empty or null.
* </p>
*
* @param text The text to check; may be null;
* @return True if the specified text is either empty or null.
* @since 4.0
*/
public static boolean isEmpty( final String text ) {
return (text == null || text.length() == 0);
}
/**
* Compare string values - considered equal if either are null or empty.
*
* @param thisValue the first value being compared (can be <code>null</code> or empty)
* @param thatValue the other value being compared (can be <code>null</code> or empty)
* @return <code>true</code> if values are equal or both values are empty
*/
public static boolean valuesAreEqual( String thisValue,
String thatValue ) {
if (isEmpty(thisValue) && isEmpty(thatValue)) {
return true;
}
return equals(thisValue, thatValue);
}
/**
* Compare string values - considered equal if either are null or empty.
* Ignores case
* @param thisValue the first value being compared (can be <code>null</code> or empty)
* @param thatValue the other value being compared (can be <code>null</code> or empty)
* @return <code>true</code> if values are equal or both values are empty
*/
public static boolean valuesAreEqualIgnoreCase( String thisValue,
String thatValue ) {
if (isEmpty(thisValue) && isEmpty(thatValue)) {
return true;
}
return equalsIgnoreCase(thisValue, thatValue);
}
/**
* Returns the index within this string of the first occurrence of the specified substring. The integer returned is the
* smallest value <i>k</i> such that: <blockquote>
*
* <pre>
* this.startsWith(str, <i>k</i>)
* </pre>
*
* </blockquote> is <code>true</code>.
*
* @param text any string.
* @param str any string.
* @return if the str argument occurs as a substring within text, then the index of the first character of the first such
* substring is returned; if it does not occur as a substring, <code>-1</code> is returned. If the text or str
* argument is null or empty then <code>-1</code> is returned.
*/
public static int indexOfIgnoreCase( final String text,
final String str ) {
if (isEmpty(text)) {
return -1;
}
if (isEmpty(str)) {
return -1;
}
final String lowerText = text.toLowerCase();
final String lowerStr = str.toLowerCase();
return lowerText.indexOf(lowerStr);
}
/**
* Tests if the string starts with the specified prefix.
*
* @param text the string to test.
* @param prefix the prefix.
* @return <code>true</code> if the character sequence represented by the argument is a prefix of the character sequence
* represented by this string; <code>false</code> otherwise. Note also that <code>true</code> will be returned if the
* prefix is an empty string or is equal to the text <code>String</code> object as determined by the
* {@link #equals(Object)} method. If the text or prefix argument is null <code>false</code> is returned.
* @since JDK1. 0
*/
public static boolean startsWithIgnoreCase( final String text,
final String prefix ) {
if (isEmpty(text)) {
return false;
}
if (prefix == null) {
return false;
}
int textLength = text.length();
int prefixLength = prefix.length();
if (prefixLength == 0) {
return true;
}
if (prefixLength > textLength) {
return false;
}
char[] chArray = prefix.toCharArray();
for (int i = 0; i != chArray.length; ++i) {
char ch1 = chArray[i];
char ch2 = text.charAt(i);
if (ch1 == ch2 || Character.toLowerCase(ch1) == Character.toLowerCase(ch2)) {
// continue
} else {
return false;
}
}
return true;
}
/**
* Tests if the string ends with the specified suffix.
*
* @param text the string to test.
* @param suffix the suffix.
* @return <code>true</code> if the character sequence represented by the argument is a suffix of the character sequence
* represented by this object; <code>false</code> otherwise. Note that the result will be <code>true</code> if the
* suffix is the empty string or is equal to this <code>String</code> object as determined by the
* {@link #equals(Object)} method. If the text or suffix argument is null <code>false</code> is returned.
*/
public static boolean endsWithIgnoreCase( final String text,
final String suffix ) {
if (isEmpty(text)) {
return false;
}
if (suffix == null) {
return false;
}
int textLength = text.length();
int suffixLength = suffix.length();
if (suffixLength == 0) {
return true;
}
if (suffixLength > textLength) {
return false;
}
int offset = textLength - suffixLength;
char[] chArray = suffix.toCharArray();
for (int i = 0; i != chArray.length; ++i) {
char ch1 = chArray[i];
char ch2 = text.charAt(offset + i);
if (ch1 == ch2 || Character.toLowerCase(ch1) == Character.toLowerCase(ch2)) {
// continue
} else {
return false;
}
}
return true;
}
/**
* Determine if the string passed in has all digits as its contents
*
* @param str
* @return true if digits; false otherwise
*/
public static boolean isDigits( String str ) {
for (int i = 0; i < str.length(); i++) {
if (!CoreStringUtil.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
// ============================================================================================================================
// Constructors
/**
* <p>
* Prevents instantiation.
* </p>
*
* @since 4.0
*/
private CoreStringUtil() {
}
/*
* Converts user string to regular expres '*' and '?' to regEx variables.
* copied from eclipse's PatternConstructor
*/
static String asRegEx( String pattern ) {
// Replace \ with \\, * with .* and ? with .
// Quote remaining characters
String result1 = Constants.PATTERN_BACK_SLASH.matcher(pattern).replaceAll("\\\\E\\\\\\\\\\\\Q"); //$NON-NLS-1$
String result2 = Constants.PATTERN_STAR.matcher(result1).replaceAll("\\\\E.*\\\\Q"); //$NON-NLS-1$
String result3 = Constants.PATTERN_QUESTION.matcher(result2).replaceAll("\\\\E.\\\\Q"); //$NON-NLS-1$
return "\\Q" + result3 + "\\E"; //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Creates a regular expression pattern from the pattern string (which is our old 'StringMatcher' format). Copied from
* Eclipse's PatternConstructor class.
*
* @param pattern The search pattern
* @param isCaseSensitive Set to <code>true</code> to create a case insensitve pattern
* @return The created pattern
*/
public static Pattern createPattern( String pattern,
boolean isCaseSensitive ) {
if (isCaseSensitive) return Pattern.compile(asRegEx(pattern));
return Pattern.compile(asRegEx(pattern), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
}
/**
* Removes extraneous whitespace from a string. By it's nature, it will be trimmed also.
*
* @param raw
* @return
* @since 5.0
*/
public static String collapseWhitespace( String raw ) {
StringBuffer rv = new StringBuffer(raw.length());
StringTokenizer izer = new StringTokenizer(raw, " "); //$NON-NLS-1$
while (izer.hasMoreTokens()) {
String tok = izer.nextToken();
// Added one last check here so we don't append a "space" on the end of the string
rv.append(tok);
if (izer.hasMoreTokens()) {
rv.append(' ');
}
} // endwhile
return rv.toString();
}
/**
* If input == null OR input.length() < desiredLength, pad to desiredLength with spaces. If input.length() > desiredLength,
* chop at desiredLength.
*
* @param input Input text
* @param desiredLength Desired length
* @return
* @since 5.0
*/
public static String toFixedLength( String input,
int desiredLength ) {
if (input == null) {
input = ""; //$NON-NLS-1$
}
if (input.length() == desiredLength) {
return input;
}
if (input.length() < desiredLength) {
StringBuffer str = new StringBuffer(input);
int needSpaces = desiredLength - input.length();
for (int i = 0; i < needSpaces; i++) {
str.append(' ');
}
return str.toString();
}
// Else too long - chop
return input.substring(0, desiredLength);
}
public static boolean isLetter( char c ) {
return isBasicLatinLetter(c) || Character.isLetter(c);
}
public static boolean isDigit( char c ) {
return isBasicLatinDigit(c) || Character.isDigit(c);
}
public static boolean isLetterOrDigit( char c ) {
return isBasicLatinLetter(c) || isBasicLatinDigit(c) || Character.isLetterOrDigit(c);
}
public static boolean isValid( String str ) {
return (!(str == null || str.trim().length() == 0));
}
public static String toUpperCase( String str ) {
String newStr = convertBasicLatinToUpper(str);
if (newStr == null) {
return str.toUpperCase();
}
return newStr;
}
public static String toLowerCase( String str ) {
String newStr = convertBasicLatinToLower(str);
if (newStr == null) {
return str.toLowerCase();
}
return newStr;
}
public static boolean isDoubleQuoted( String str ) {
return str.startsWith(Constants.DQUOTE_STR) && str.endsWith(Constants.DQUOTE_STR) && isTwoDoubleQuotes(str);
}
public static boolean isTwoDoubleQuotes( String str ) {
int result = 0;
for( char nextChar : str.toCharArray() ) {
if( nextChar == Constants.DQUOTE_CHAR) {
if( result == 2 ) {
result = 1;
} else {
result++;
}
}
}
return result == 2;
}
/**
* Create a valid filename from the given String.
*
* @param str The String to convert to a valid filename.
* @param defaultName The default name to use if only special characters exist.
* @return String A valid filename.
*/
public static String createFileName( String str ) {
/** Replace some special chars */
str = str.replaceAll(" \\| ", "_"); //$NON-NLS-1$ //$NON-NLS-2$
str = str.replaceAll(">", "_"); //$NON-NLS-1$ //$NON-NLS-2$
str = str.replaceAll(": ", "_"); //$NON-NLS-1$ //$NON-NLS-2$
str = str.replaceAll(" ", "_"); //$NON-NLS-1$ //$NON-NLS-2$
str = str.replaceAll("\\?", "_"); //$NON-NLS-1$ //$NON-NLS-2$
str = str.replaceAll("/", "_"); //$NON-NLS-1$ //$NON-NLS-2$
/** If filename only contains of special chars */
if (str.matches("[_]+")) //$NON-NLS-1$
str = "file"; //$NON-NLS-1$
return str;
}
/**
* Make the first letter uppercase
*
* @param str
* @return The string with the first letter being changed to uppercase
* @since 5.5
*/
public static String firstLetterUppercase( String str ) {
if (str == null || str.length() == 0) {
return null;
}
if (str.length() == 1) {
return str.toUpperCase();
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
private static String convertBasicLatinToUpper( String str ) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (isBasicLatinLowerCase(chars[i])) {
chars[i] = (char)('A' + (chars[i] - 'a'));
} else if (!isBasicLatinChar(chars[i])) {
return null;
}
}
return new String(chars);
}
private static String convertBasicLatinToLower( String str ) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (isBasicLatinUpperCase(chars[i])) {
chars[i] = (char)('a' + (chars[i] - 'A'));
} else if (!isBasicLatinChar(chars[i])) {
return null;
}
}
return new String(chars);
}
private static boolean isBasicLatinUpperCase( char c ) {
return c >= 'A' && c <= 'Z';
}
private static boolean isBasicLatinLowerCase( char c ) {
return c >= 'a' && c <= 'z';
}
private static boolean isBasicLatinLetter( char c ) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
private static boolean isBasicLatinDigit( char c ) {
return c >= '0' && c <= '9';
}
private static boolean isBasicLatinChar( char c ) {
return c <= '\u007F';
}
/**
* Convert the given value to specified type.
*
* @param value
* @param type
* @return
*/
@SuppressWarnings( "unchecked" )
public static <T> T valueOf( String value,
Class type ) {
if (type == String.class) {
return (T)value;
} else if (type == Boolean.class || type == Boolean.TYPE) {
return (T)Boolean.valueOf(value);
} else if (type == Integer.class || type == Integer.TYPE) {
return (T)Integer.decode(value);
} else if (type == Float.class || type == Float.TYPE) {
return (T)Float.valueOf(value);
} else if (type == Double.class || type == Double.TYPE) {
return (T)Double.valueOf(value);
} else if (type == Long.class || type == Long.TYPE) {
return (T)Long.decode(value);
} else if (type == Short.class || type == Short.TYPE) {
return (T)Short.decode(value);
} else if (type.isAssignableFrom(List.class)) {
return (T)new ArrayList<String>(Arrays.asList(value.split(","))); //$NON-NLS-1$
} else if (type.isArray()) {
String[] values = value.split(","); //$NON-NLS-1$
Object array = Array.newInstance(type.getComponentType(), values.length);
for (int i = 0; i < values.length; i++) {
Array.set(array, i, valueOf(values[i], type.getComponentType()));
}
return (T)array;
} else if (type == Void.class) {
return null;
} else if (type.isEnum()) {
return (T)Enum.valueOf(type, value);
}
else if (type.isAssignableFrom(Map.class)) {
List<String> l = Arrays.asList(value.split(",")); //$NON-NLS-1$
Map m = new HashMap<String, String>();
for (String key : l) {
int index = key.indexOf('=');
if (index != -1) {
m.put(key.substring(0, index), key.substring(index + 1));
}
}
return (T)m;
}
throw new IllegalArgumentException("Conversion from String to " + type.getName() + " is not supported"); //$NON-NLS-1$ //$NON-NLS-2$
}
public static String[] getLines( final String value ) {
StringReader stringReader = new StringReader(value);
BufferedReader reader = new BufferedReader(stringReader);
ArrayList result = new ArrayList();
try {
String line = reader.readLine();
while (line != null) {
result.add(line);
line = reader.readLine();
}
} catch (IOException e) {
throw new TeiidDesignerRuntimeException(e);
}
return (String[])result.toArray(new String[result.size()]);
}
/**
* @param thisString the first string being compared (may be <code>null</code>)
* @param thatString the other string being compared (may be <code>null</code>)
* @return <code>true</code> if the supplied strings are both <code>null</code> or have equal values
*/
public static boolean equals( final String thisString,
final String thatString ) {
if (thisString == null) {
return (thatString == null);
}
return thisString.equals(thatString);
}
/**
* @param thisString the first string being compared (may be <code>null</code>)
* @param thatString the other string being compared (may be <code>null</code>)
* @return <code>true</code> if the supplied strings are both <code>null</code> or have equal values, (ignoring case)
*/
public static boolean equalsIgnoreCase( final String thisString,
final String thatString ) {
if (thisString == null) {
return (thatString == null);
}
return thisString.equalsIgnoreCase(thatString);
}
}