/*
* This software is distributed under the terms of the FSF
* Gnu Lesser General Public License (see lgpl.txt).
*
* This program is distributed WITHOUT ANY WARRANTY. See the
* GNU General Public License for more details.
*/
package com.scooterframework.common.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* StringUtil class has methods on string manipulation.
*
* @author (Fei) John Chen
*/
public class StringUtil {
/**
* Returns the first few characters of a string. The rest is replaced by
* "...".
*
* @param s the original string
* @param length the number of characters to be returned.
* @return the first <tt>length</tt> characters of a string
*/
public static String preview(String s, int length) {
return preview(s, length, "...");
}
/**
* Returns the first few characters of a string. The rest is replaced by
* <tt>tail</tt>.
*
* @param s the original string
* @param length the number of characters to be returned.
* @param tail the symbol of the remaining part of the string.
* @return the first <tt>length</tt> characters of a string
*/
public static String preview(String s, int length, String tail) {
if (s == null || s.length() <= length) return s;
return s.substring(0, length-1) + " " + tail;
}
/**
* Returns length of a string. If the string is null, return 0.
*
* @param data input string
* @return 0 if the data is null or the length of the data string.
*/
public static int strlen(String data) {
return (data == null)?0:data.length();
}
/**
* Returns a string with all alphabetic characters converted to lower case.
*
* @param s input string
* @return a string in lower case.
*/
public static String toLowerCase(String s) {
return (s != null)?s.toLowerCase():s;
}
/**
* Returns a string with all alphabetic characters converted to upper case.
*
* @param s input string
* @return a string in upper case.
*/
public static String toUpperCase(String s) {
return (s != null)?s.toUpperCase():s;
}
/**
* Checks if a string starts with lower case char.
* @param s the string to check
* @return true if the string starts with lower case char.
*/
public static boolean startsWithLowerCaseChar(String s) {
int c0 = (int)s.charAt(0);
return (c0 >= 97 && c0 <= 122)?true:false;
}
/**
* Replaces old symbols with an empty string.
*
* <pre>
* Examples:
* replace("123te123ch123", "123"); would return "tech"
* </pre>
*
* @param data the original string
* @param oldSymbol the substring to be replaced
* @return a replaced string
*/
public static String replace(String data, String oldSymbol) {
return replace(data, oldSymbol, "");
}
/**
* Replaces old symbols with new symbols in a string.
*
* <pre>
* Examples:
* replace("123te123ch123", "123", "X"); would return "XteXchX"
* </pre>
*
* @param s the original string
* @param oldSymbol the substring to be replaced
* @param newSymbol the replacement substring
* @return a replaced string
*/
public static String replace(String s, String oldSymbol, String newSymbol) {
// In a string replace one substring with another
if (s == null || s.indexOf(oldSymbol) == -1) return s;
int oldLength = oldSymbol.length();
StringBuilder sb = new StringBuilder("");
int i = s.indexOf(oldSymbol,0);
int lastIndex = 0;
while (i != -1) {
sb.append(s.substring(lastIndex,i)).append(newSymbol);
lastIndex = i + oldLength;
i = s.indexOf(oldSymbol, lastIndex);
}
sb.append(s.substring(lastIndex));
return sb.toString();
}
/**
* Replaces the last occurance of an old symbol with a new symbol.
*
* @param s the original string
* @param oldSymbol the substring to be replaced
* @param newSymbol the replacement substring
* @return a replaced string
*/
public static String replaceLast(String s, String oldSymbol, String newSymbol) {
if (s == null || s.indexOf(oldSymbol) == -1) return s;
int lastIndex = s.lastIndexOf(oldSymbol);
int oldLength = oldSymbol.length();
String result = s.substring(0, lastIndex) + newSymbol +
s.substring(lastIndex + oldLength);
return result;
}
/**
* Removes all occurances of the characters in <tt>charsToBeremoved</tt>.
*
* <pre>
* Examples:
* remove("abcabc1234567", "abc"); would return "1234567"
* </pre>
*
* @param message the string to be processed
* @param charsToBeremoved a string containing characters to be removed
* @return a new string
*/
public static String remove(String message, String charsToBeremoved) {
return translate(message, charsToBeremoved, null);
}
/**
* <tt>translate</tt> method replaces a sequence of characters in a
* string with another set of characters. However, it replaces a single
* character at a time. For example, it will replace the 1st character in
* the <tt>charsToBeReplaced</tt> with the 1st character in the
* <tt>replacementChars</tt>. Then it will replace the 2nd character in
* the <tt>charsToBeReplaced</tt> with the 2nd character in the
* <tt>replacementChars</tt>, and so on.
*
* The length of <tt>charsToBeReplaced</tt> should be the same as
* <tt>replacementChars</tt>. If the <tt>replacementChars</tt>
* string is empty, then all occurances of the characters in
* <tt>charsToBeReplaced</tt> are replaced with empty character.
*
* <pre>
* Examples:
* translate("Hello!", "eo", "oa"); would return "Holla!"
* translate("123456", "23", "98"); would return "198456"
* translate("abcabc1234567", "abc", "000"); would return "0000001234567".
* </pre>
*
* @param message the string to be translated
* @param charsToBeReplaced characters to be replaced
* @param replacementChars characters to be used as replacement
* @return a new translated string
*/
public static String translate(String message, String charsToBeReplaced, String replacementChars) {
if (message == null) return message;
boolean useEmpty = false;
if (replacementChars == null || "".equals(replacementChars)) useEmpty = true;
if (!useEmpty && (replacementChars.length() != charsToBeReplaced.length()))
throw new IllegalArgumentException("The replacement characters are not of the same length of the replaced characters.");
StringBuilder sb = new StringBuilder("");
int length = message.length();
for (int i=0; i<length; i++) {
char c = message.charAt(i);
int index = charsToBeReplaced.indexOf(c);
if (index != -1) {
if (!useEmpty) {
sb.append(replacementChars.charAt(index));
}
}
else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Removes slash from a string.
*
* @param s the original string
* @return a string without slash
*/
public static String stripSlashes(String s) {
if (s == null || s.indexOf('/') == -1) return s;
return replace(s, "/", "");
}
/**
* Converts a string of name and value pairs, separated by a separator to
* map. The separator could be comma, or vertical slash or space, etc.
*
* <pre>
* String data has the following format:
* firstName=John, lastName=Doe, age=10,...
* or firstName=John|lastName=Doe|age=10|...
* </pre>
*
* @param data
* @param separator
* @return Map<String, Object>
*/
public Map<String, String> explode(String data, String separator) {
return Converters.convertStringToMap(data, separator);
}
/**
* Converts a list of strings into a long string separated by glue.
*
* @param data string array
* @param glue
* @return String
*/
public static String implode(String[] data, String glue) {
if (data == null || data.length ==0) return "";
StringBuilder sb = new StringBuilder();
int total = data.length;
for (int i = 0; i < total; i++) {
String item = data[i];
sb.append(item).append(glue);
}
String result = sb.toString();
if (result.endsWith(glue)) result = result.substring(0, result.lastIndexOf(glue));
return result;
}
/**
* Converts a list of strings into a long string separated by glue.
*
* @param data a list of strings
* @param glue
* @return String
*/
public static String implode(List<String> data, String glue) {
if (data == null || data.size() ==0) return "";
StringBuilder sb = new StringBuilder();
Iterator<String> it = data.iterator();
while(it.hasNext()) {
String item = it.next();
sb.append(item).append(glue);
}
String result = sb.toString();
if (result.endsWith(glue)) result = result.substring(0, result.lastIndexOf(glue));
return result;
}
/**
* Converts map into a long string separated by glue.
*
* @param data a map
* @param glue
* @return String
*/
public static String implode(Map<String, ?> data, String glue) {
if (data == null || data.size() ==0) return "";
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, ?> entry : data.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append(glue);
}
String result = sb.toString();
if (result.endsWith(glue)) result = result.substring(0, result.lastIndexOf(glue));
return result;
}
/**
* Converts object array to a big string separated by comma.
*
* @param words
* @return a flattened string
*/
public static String flattenArray(Object[] words) {
return flattenArray(words, ",");
}
/**
* Converts object array to a big string separated by splitter.
*
* @param words
* @param splitter
* @return a flattened string
*/
public static String flattenArray(Object[] words, String splitter) {
return flattenArray("", words, splitter);
}
/**
* Converts object array to a big string separated by splitter.
*
* @param prefix prefix before each element
* @param words an array of elements
* @param splitter a string which separates each element
* @return a flattened string
*/
public static String flattenArray(String prefix, Object[] words, String splitter) {
if (words == null) return null;
StringBuilder sb = new StringBuilder("");
int length = words.length;
for (int i=0; i<length; i++) {
sb.append(prefix).append(words[i]).append(splitter);
}
return removeLastToken(sb.toString(), splitter);
}
/**
* Split a string into a list of substrings separated by splitter.
*
* @param bigString The string to be split
* @param splitter The splitter
* @return a list of strings
*/
public static List<String> splitString(String bigString, String splitter) {
if (bigString == null || "".equals(bigString.trim())) return new ArrayList<String>();
List<String> dataList = new ArrayList<String>();
int spliterLen = splitter.length();
int index = bigString.indexOf(splitter);
while(index != -1) {
String frontString = bigString.substring(0, index);
dataList.add(frontString);
bigString = bigString.substring(index+spliterLen);
index = bigString.indexOf(splitter);
}
if (!bigString.equals("")) dataList.add(bigString);
//add the original string to the return list if nothing is split.
if (dataList.size() == 0) dataList.add(bigString);
return dataList;
}
/**
* Check if the string array contains the item. String case is ignored
* when doing the check.
*
* @param item
* @param array
* @return true if the string array contains the item.
*/
public static boolean isStringInArray(String item, String[] array) {
return isStringInArray(item, array, false);
}
/**
* Check if the string array contains the item.
*
* @param item
* @param array
* @param ignoreCase true if case is ignored when doing comparison.
* @return true if the string array contains the item.
*/
public static boolean isStringInArray(String item, String[] array, boolean ignoreCase) {
if (array == null) return false;
boolean result = false;
int size = array.length;
for (int i = 0; i < size; i++) {
String tmp = array[i];
if (tmp != null) {
if (ignoreCase) {
if (tmp.equalsIgnoreCase(item)) {
result = true;
break;
}
}
else {
if (tmp.equals(item)) {
result = true;
break;
}
}
}
else {
if (item == null) {
result = true;
break;
}
}
}
return result;
}
public static StringBuffer removeLastToken(StringBuffer word, String token) {
if (word == null) return word;
String newWord = removeLastToken(word.toString(), token);
return new StringBuffer(newWord);
}
public static StringBuilder removeLastToken(StringBuilder word, String token) {
if (word == null) return word;
String newWord = removeLastToken(word.toString(), token);
return new StringBuilder(newWord);
}
public static String removeLastToken(String word, String token) {
return (word == null || token == null || "".equals(token) ||
!word.endsWith(token)) ?
word :
word.substring(0, word.length()- token.length());
}
public static String reverseMapping(String mapping) {
if (mapping == null) return null;
Map<String, String> m = Converters.convertStringToMap(mapping);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : m.entrySet()) {
sb.append(entry.getValue()).append("=").append(entry.getKey()).append(",");
}
return removeLastToken(sb.toString(), ",");
}
public static String getValuesAsSQLNumber(Collection<String> values) {
if (values == null) return null;
StringBuilder sb = new StringBuilder("");
int i = 0;
Object[] data = values.toArray();
for (i = 0; i < (values.size() - 1); i++) {
sb.append(data[i]).append(", ");
}
if (values.size() >= 1) sb.append(data[i]);
return sb.toString();
}
public static String getValuesAsSQLString(Collection<String> values) {
if (values == null) return null;
StringBuilder sb = new StringBuilder("");
int i = 0;
Object[] data = values.toArray();
for (i = 0; i < (values.size() - 1); i++) {
sb.append("'").append(doubleSingleQuoteInString((String) data[i])).append("', ");
}
sb.append("'").append(doubleSingleQuoteInString((String) data[i])).append("'");
return sb.toString();
}
public static String getValuesAsSQLString(String value) {
if (value == null || value.equals("")) return value;
StringTokenizer st = new StringTokenizer(value, ", ");
StringBuilder listStr = new StringBuilder("");
while (st.hasMoreTokens()) {
String tmp = st.nextToken();
listStr.append("'").append(doubleSingleQuoteInString(tmp)).append("',");
}
return removeLastToken(listStr.toString(), ",");
}
public static String getValuesAsSQLLikeString(String field, List<String> values, String type) {
if (field == null || values == null || values.size() < 1 || type == null) return null;
StringBuilder sb = new StringBuilder("");
int i = 0;
sb.append(" UPPER(").append(field).append(") LIKE '%");
sb.append(toUpperCase(doubleSingleQuoteInString(values.get(i)))).append("%' ");
for (i = 1; i < values.size(); i++) {
sb.append(type).append(" UPPER(").append(field).append(") LIKE '%");
sb.append(toUpperCase(doubleSingleQuoteInString(values.get(i)))).append("%' ");
}
return sb.toString();
}
/**
* Adds another single quote if there is already one in the input string.
*/
public static String doubleSingleQuoteInString(String input) {
if (input == null || input.equals("")) return input;
StringBuilder result = new StringBuilder("");
while(input.indexOf("'") != -1) {
int iQ = input.indexOf("'");
result.append(input.substring(0, iQ+1)).append("'");
if ((iQ + 1) <= input.length()) input = input.substring(iQ+1);
}
result.append(input);
return result.toString();
}
// add a back slash in front of "
public static String parseStringForDoubleQuote(String input) {
if (input == null || input.equals("")) return input;
StringBuilder result = new StringBuilder("");
while(input.indexOf("\"") != -1) {
int iQ = input.indexOf("\"");
result.append(input.substring(0, iQ)).append("\\\"");
if ((iQ + 1) <= input.length()) input = input.substring(iQ + 1);
}
result.append(input);
return result.toString();
}
/**
* Converts all keys in a map to upper case.
*
* @param inputs the original map
* @return a new map with keys in upper case.
*/
public static Map<String, Object> convertKeyToUpperCase(Map<String, ?> inputs) {
if (inputs == null) return null;
Map<String, Object> tmp = new HashMap<String, Object>(inputs.size());
for(Map.Entry<String, ?> entry : inputs.entrySet()) {
String key = entry.getKey();
tmp.put(toUpperCase(key), entry.getValue());
}
return tmp;
}
}