/*
* $Id: StringHandler.java,v 1.51 2009/05/20 14:19:05 valdas Exp $ Created on
* 14.9.2004
*
* Copyright (C) 2001-2004 Idega Software hf. All Rights Reserved.
*
* This software is the proprietary information of Idega hf. Use is subject to
* license terms.
*/
package com.idega.util;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.idega.presentation.IWContext;
/**
* This class has utility methods to work with strings. <br>
* Last modified: $Date: 2009/05/20 14:19:05 $ by $Author: valdas $
*
* @author <a href="mailto:tryggvi@idega.is">Tryggvi Larusson </a>, <a
* href="mailto:gummi@idega.is">Gudmundur Saemundsson </a>
* @version $Revision: 1.51 $
*/
public class StringHandler {
/**
* substitution string if a character is not a letter
*/
public static String NO_LETTER_SUBSTITUTION = "-";
/**
* groups of characters (represented by uni code) replaced by strings
* defined in substitution. Use the uni code table (@see
* http:\\www.unicode.org)
*/
static public int[][] SUBSTITUTION_GROUP = {
// 192 - 207
{ 192, 193, 194, 195, 196, 197 }, // A
{ 198 }, // Ae
{ 199 }, // C
{ 200, 201, 202, 203 }, // E
{ 204, 205, 206, 207 }, // I
// 208 - 223
{ 208 }, // D
{ 209 }, // N
{ 210, 211, 212, 213, 214 }, // O
{ 215 }, // x - char 215 is no letter
{ 216 }, // O
{ 217, 218, 219, 220 }, // U
{ 221 }, // Y
{ 222 }, // Th
{ 223 }, // ss
// 224 - 239
{ 224, 225, 226, 227, 228, 229 }, // a
{ 230 }, // ae
{ 231 }, // c
{ 232, 233, 234, 235 }, // e
{ 236, 237, 238, 239 }, // i
// 240 - 255
{ 240 }, // d
{ 241 }, // n
{ 242, 243, 244, 245, 246 }, // o
{ 247 }, // x char 247 is no letter
{ 248 }, // o
{ 249, 250, 251, 252 }, // u
{ 253 }, // y
{ 254 }, // th
{ 255 }, // y
// Latin Extended-A
{ 0x0100, 0x0102, 0x0104 }, // A
{ 0x0101, 0x0103, 0x0105 }, // a
{ 0x0106, 0x0108, 0x010A, 0x010C }, // C
{ 0x0107, 0x0109, 0x010B, 0x010D }, // c
{ 0x010E, 0x0110 }, // D
{ 0x010F, 0x0111 }, // d
{ 0x0112, 0x0114, 0x0116, 0x0118, 0x011A }, // E
{ 0x0113, 0x0115, 0x0117, 0x0119, 0x011B }, // e
{ 0x011C, 0x011E, 0x0120, 0x0122 }, // G
{ 0x011D, 0x011F, 0x0121, 0x0123 }, // g
{ 0x0124, 0x0126 }, // H
{ 0x0125, 0x0127 }, // h
{ 0x0128, 0x012A, 0x012C, 0x012E, 0x0130 }, // I
{ 0x0129, 0x012B, 0x012D, 0x012F, 0x0131 }, // i
{ 0x0132 }, // IJ
{ 0x0133 }, // ij
{ 0x0134 }, // J
{ 0x0135 }, // j
{ 0x0136 }, // K
{ 0x0137 }, // k
{ 0x0138 }, // kra
{ 0x0139, 0x013B, 0x013D, 0x013F, 0x0141 }, // L
{ 0x013A, 0x013C, 0x013E, 0x0140, 0x0142 }, // l
{ 0x0143, 0x0145, 0x0147 }, // N
{ 0x0144, 0x0146, 0x0148, 0x0149 }, // n
{ 0x014A }, // ENG
{ 0x014B }, // eng
{ 0x014C, 0x014E, 0x0150 }, // O
{ 0x014D, 0x014F, 0x0151 }, // o
{ 0x0152 }, // OE
{ 0x0153 }, // oe
{ 0x0154, 0x0156, 0x0158 }, // R
{ 0x0155, 0x0157, 0x0159 }, // r
{ 0x015A, 0x015C, 0x015E, 0x0160 }, // S
{ 0x015B, 0x015D, 0x015F, 0x0161 }, // s
{ 0x0162, 0x0164, 0x0166 }, // T
{ 0x0163, 0x0165, 0x0167 }, // t
{ 0x0168, 0x016A, 0x016C, 0x016E, 0x0170, 0x0172 }, // U
{ 0x0169, 0x016B, 0x016D, 0x016F, 0x0171, 0x0173 }, // u
{ 0x0174 }, // W
{ 0x0175 }, // w
{ 0x0176, 0x0178 }, // Y
{ 0x0177 }, // y
{ 0x0179, 0x017B, 0x017D }, // Z
{ 0x017A, 0x017C, 0x017E }, // z
{ 0x017F }, // s
};
private static final int SUBSTITUTED_MIN = 192;
private static final int SUBSTITUTED_MAX = 0x017F;
/**
* substitution strings for characters defined in substitution group
*/
static public String[] SUBSTITUTION = { "A", "Ae", "C", "E", "I", "D", "N", "O", NO_LETTER_SUBSTITUTION, "O", "U",
"Y", "Th", "ss", "a", "ae", "c", "e", "i", "d", "n", "o", NO_LETTER_SUBSTITUTION, "o", "u", "y", "th", "y",
"A", "a", "C", "c", "D", "d", "E", "e", "G", "g", "H", "h", "I", "i", "IJ", "ij", "J", "j",
"K", "k", "kra", "L", "l", "N", "n", "ENG", "eng", "O", "o", "OE", "oe", "R", "r", "S", "s",
"T", "t", "U", "u", "W", "w", "Y", "y", "Z", "z", "s",
};
public static String alfabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// Alphabet+Numbers without ambigous characters such as 0 O and I l and 1
public static String alphabetNonAmbigous = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefhijkmnoprstuvwxyz23456789";
public static final String EMPTY_STRING = "";
public static final String DASH = "-";
public static final String SLASH = "/";
public static final String NEWLINE = "\n";
public static final String SPACE = " ";
public static final String SEMICOLON = ";";
public static final String COLON = ":";
public StringHandler() {
// empty blocks
}
/**
* Returns an random String with the desired length with the Roman alphabet
* (upper and lower case) and numbers 0-9
*/
public static String getRandomString(int length) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
buffer.append(alfabet.charAt((int) (alfabet.length() * Math.random())));
}
return buffer.toString();
}
/**
* Returns an random String with the desired length with the Roman alphabet
* (upper and lower case) without ambigous characters (which can be confused
* together) and numbers 2-9
*/
public static String getRandomStringNonAmbiguous(int length) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
buffer.append(alphabetNonAmbigous.charAt((int) (alphabetNonAmbigous.length() * Math.random())));
}
return buffer.toString();
}
/**
* Concatenates two strings to after alphabetical comparison
*/
public static String concatAlphabetically(String string1, String string2, String separator) {
String first;
String second;
int compare = string1.compareTo(string2);
if (compare < 0) {
first = string1;
second = string2;
}
else {
second = string1;
first = string2;
}
return first + separator + second;
}
public static String concat(String firstString, String secondString) {
StringBuffer buffer = new StringBuffer(firstString);
buffer.append(secondString);
return buffer.toString();
}
public static String concatAlphabetically(String string1, String string2) {
return concatAlphabetically(string1, string2, "");
}
public static Iterator getSeparatorIterator(final String stringToCutDown, final String separator) {
return new Iterator() {
private String theString = stringToCutDown;
private String theSeparator = separator;
private boolean hasSeparators = false;
private boolean hasNext = true;
@Override
public Object next() throws NoSuchElementException {
String theReturn = null;
try {
if (this.hasNext) {
if (this.hasSeparators) {
if (this.theString.length() > 0) {
if (!this.theString.equals(this.theSeparator)) {
theReturn = this.theString.substring(0, this.theString.indexOf(separator) + 1);
this.theString = this.theString.substring(this.theString.indexOf(separator) + 1,
this.theString.length());
}
}
else {
throw new NoSuchElementException();
}
}
else {
if (this.theString.length() > 0) {
return this.theString;
}
throw new NoSuchElementException();
}
}
else {
throw new NoSuchElementException();
}
}
catch (Exception e) {
if (e instanceof NoSuchElementException) {
throw (NoSuchElementException) e.fillInStackTrace();
}
throw new NoSuchElementException();
}
return theReturn;
}
@Override
public boolean hasNext() {
if (this.theString != null) {
if (this.theString.length() > 0) {
int index = this.theString.indexOf(this.theSeparator);
while (index == 0) {
this.theString = this.theString.substring(0, this.theSeparator.length());
index = this.theString.indexOf(this.theSeparator);
}
if (index == -1) {
this.hasSeparators = false;
}
else {
this.hasSeparators = true;
}
}
else {
this.hasNext = false;
}
}
else {
this.hasNext = false;
}
return this.hasNext;
}
@Override
public void remove() {
/**
*
* Does Nothing
*
*/
}
};
}
private static final char[] empty_char_array={};
/**
* Strips the string of all non-roman characters such as special
* Icelandic,Swedish,German etc. characters. <br>
* This method replaces these characters and re-writes them with Roman
* equivalents. <br>
* So '�'/Þ becomes TH, '�'/á becomes a, '�'/ä becomes ae,
* etc.
*/
public static String stripNonRomanCharacters(String inputString) {
return stripNonRomanCharacters(inputString,empty_char_array);
}
/**
* Strips the string of all non-roman characters such as special
* Icelandic,Swedish,German etc. characters. <br>
* This method replaces these characters and re-writes them with Roman
* equivalents. <br>
* So '�'/Þ becomes Th, '�'/á becomes a, '�'/ä becomes ae,
* etc.
* @param inputString the input string to replace
* @param exceptions an array of characters to maintain in the outputString
*/
public static String stripNonRomanCharacters(String inputString,char[] exceptions) {
char[] cAinputString = inputString.toCharArray();
StringBuffer newString = new StringBuffer();
Arrays.sort(exceptions);
for (int i = 0; i < cAinputString.length; i++) {
char c = cAinputString[i];
newString.append(translateNonRomanCharacter(c,exceptions));
}
return newString.toString();
}
/**
* Returns true if the specified object returns an empty string or null when the
* toString() method is invoked else false.
*/
public static boolean isEmpty(Object element) {
return ! isNotEmpty(element);
}
/**
* Returns true if the specified object returns a non empty string when the
* toString() method is invoked else false.
*/
public static boolean isNotEmpty(Object element) {
if (element == null) {
return false;
}
String aString = element.toString();
return (aString != null && aString.length() > 0);
}
/**
* Returns true if each element of the collection returns a non empty string
* when the toString() method is invoked else false.
*/
public static boolean elementsAreNotEmpty(Collection collection) {
if (collection == null || collection.isEmpty()) {
return false;
}
Iterator iter = collection.iterator();
while (iter.hasNext()) {
Object element = iter.next();
String aString = element.toString();
if (!StringHandler.isNotEmpty(aString)) {
return false;
}
}
return true;
}
/**
*
* <p>
* Returns only the first token corresponding to the specified
* delimiters.
* </p>
* <p>
* e.g. getFirstToken("hello_wo.rld", "_.") returns "hello" <br>
* e.g. getFirstToken("hello.world_txt", "_.") returns "hello" <br>
* e.g. getFirstToken("helloWorld", "_.") returns "helloWorld"
* </p>
* @param str
* @param delim
* @return
*/
public static String getFirstToken(String str, String delim) {
char[] delimChars = delim.toCharArray();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Arrays.binarySearch(delimChars, c) >= 0) {
// found
return str.substring(0, i);
}
}
return str;
}
/**
* Returns the package name and the name of the specified className.
* Example: "com.idega.util.StringHandler" returns {"com.idega.util",
* "StringHandler"} "StringHandler" returns {"", "StringHandler"}
*
* @param className
* @return array containing the package name and the class name without
* package name
*/
public static String[] splitOffPackageFromClassName(String className) {
String packageName;
String name;
int index = className.lastIndexOf(".");
if (index < 0) {
packageName = "";
name = className;
}
else {
packageName = className.substring(0, index);
name = className.substring(++index);
}
return new String[] { packageName, name };
}
/**
* Returns the specified filename without extension but not if the fileName
* starts with a dot character. Example: cutExtension("tomcat.gif") returns
* "tomcat"; cutExtension("tomcat") returns "tomcat";
* cutExtension(".systemFile") returns ".systemFile";
*
* @param fileName
* @return name without extension
*/
public static String cutExtension(String fileName) {
int index = fileName.lastIndexOf(".");
if (index <= 0) {
return fileName;
}
return fileName.substring(0, index);
}
public static String replaceNameKeepExtension(String oldFileNameWithExtension, String newFileNameWithoutExtension) {
int index = oldFileNameWithExtension.lastIndexOf(".");
if (index <= 0) {
return newFileNameWithoutExtension;
}
String extension = oldFileNameWithExtension.substring(index);
return StringHandler.concat(newFileNameWithoutExtension, extension);
}
/**
* Marks all occurences of the specified pattern in the specified string
* with the specified replace in a map, ignores case. The caller can modify
* the specified string later by using the keys of the map (they corrrespond
* to the index in the string sarting at zero). This method is useful when
* more than one key has to be replaced and some keys appear in the replace
* strings. Example: getReplaceMapIgnoreCase("A cat is not a caterpillar",
* "cat", "rat") returns a map with the following entries: ( 2,"ra") ( 3,
* null) (16, "ra") (17, null) getReplaceMapIgnoreCase("A cat is not a
* caterpillar", "r", "ur") returns the following map (20, "ur") (26, "ur")
* By adding the maps and replacing the characters according to the keys the
* result is: "A rat is not a rateurpillaur"
*/
public static Map getReplaceMapIgnoreCase(String str, String pattern, String replace) {
Map indexMap = new HashMap();
int s = 0;
int e = 0;
String upperPattern = pattern.toUpperCase();
int length = upperPattern.length();
String upperStr = str.toUpperCase();
while ((e = upperStr.indexOf(upperPattern, s)) >= 0) {
indexMap.put(new Integer(e), replace);
int i = e;
i++;
while (i < e + length) {
indexMap.put(new Integer(i++), null);
}
s = i;
}
return indexMap;
}
/**
* Replaces all occurences of the specified pattern in the specified string
* with the specified replace, ignores case. Example: replaceIgnoreCase("A
* CAT is not a caterpillar", "ca", "hu") returns "A hut is not a
* huterpillar"
*
* @param str
* @param pattern
* @param replace
* @return modified (new) string
* @author thomas
*/
public static String replaceIgnoreCase(String str, String pattern, String replace) {
int s = 0;
int e = 0;
String upperPattern = pattern.toUpperCase();
String upperStr = str.toUpperCase();
StringBuffer result = new StringBuffer();
while ((e = upperStr.indexOf(upperPattern, s)) >= 0) {
result.append(str.substring(s, e));
result.append(replace);
s = e + upperPattern.length();
}
result.append(str.substring(s));
return result.toString();
}
/**
* Returns the replacement if the specified string is empty else the
* specified string
*
* @param aString
* @param replacement
* @return
*/
public static String replaceIfEmpty(String aString, String replacement) {
if (aString == null || aString.length() == 0) {
return replacement;
}
return aString;
}
/**
* Replaces all occurences of the specified pattern in the specified string
* with the specified replace Example: replace("A cat is not a caterpillar",
* "ca", "hu") returns "A hut is not a huterpillar"
*
* @param str
* @param pattern
* @param replace
* @return modified (new) string
* @author thomas
*/
public static String replace(String str, String pattern, String replace) {
if (StringUtil.isEmpty(str)) {
return str;
}
int s = 0;
int e = 0;
StringBuffer result = new StringBuffer();
while ((e = str.indexOf(pattern, s)) >= 0) {
result.append(str.substring(s, e));
result.append(replace);
s = e + pattern.length();
}
result.append(str.substring(s));
return result.toString();
}
/**
* Removes all occurences of the specified pattern from the specified
* string. Example: replace("A cat is not a caterpillar", "ca") returns "A t
* is not a terpillar"
*
* @param str
* @param pattern
* @return modified (new) string
* @author thomas
*/
public static String remove(String str, String pattern) {
int s = 0;
int e = 0;
StringBuffer result = new StringBuffer();
while ((e = str.indexOf(pattern, s)) >= 0) {
result.append(str.substring(s, e));
s = e + pattern.length();
}
result.append(str.substring(s));
return result.toString();
}
/**
* Removes all occurences of white spaces from the specified string.
* Example: replace("A cat is not a caterpillar") returns
* "Acatisnotacaterpillar"
*
* @param str
* @param pattern
* @return modified (new) string
* @author thomas
*/
public static String removeWhiteSpace(String str) {
return StringHandler.remove(str, " ");
}
/**
* Gets the words that are contained in a string corresponding to a list of
* allowed words. If the string contains a non allowed word an empty list
* ist returned. Ignores case and returns only words in upper case. Example:
* list = "(" ")" "or" "xor" "A" "B" getElements("A OR(B xor C)", list,
* false) returns "(" "A" "OR" "(" "B" "XOR" "C" ")"
*
* @param str
* @param allowedWords
* @param list
* of allowed words in str else null
* @param case
* sensitivity
* @author thomas
*/
public static List getElementsIgnoreCase(String str, Collection allowedWords) {
List words = new ArrayList(allowedWords.size());
String string = str.toUpperCase();
Iterator iterator = allowedWords.iterator();
while (iterator.hasNext()) {
String word = (String) iterator.next();
words.add(word.toUpperCase());
}
return getElements(string, words);
}
/**
* Gets the substring that is enclosed by the specified strings. If one of
* the parameters is null null is returned. Examples:
* substring("caterpillar","cat", "a") returns "erpill"
* substring("caterpillar","we", "a") returns null substring
* ("caterpillar","","a") returns "caterpill" substring("caterpillar", "",
* "") returns "caterpillar" substring("caterpillar","a", "l") returns
* "terpil" substring("","","") returns "" substring(null, "cat", "we")
* returns null substring("caterpillar", null, "we") returns null
*
* @param string
* @param start
* @param end
* @return sunbstring
* @author thomas
*/
public static String substringEnclosedBy(String string, String start, String end) {
if (string == null || start == null || end == null) {
return null;
}
int startIndex = string.indexOf(start);
if (startIndex == -1) {
return null;
}
int endIndex = string.lastIndexOf(end);
if (endIndex == -1) {
return null;
}
startIndex += start.length();
return string.substring(startIndex, endIndex);
}
/**
* Returns a string with an added or increased counter depending on the
* specified token. The returned string is unique regarding the specified
* collection of strings. If the string is already unique the string is not
* modified. Null strings are handled like empty strings. If the
* collectionOfString parameter is null the specified string is returned.
* Examples: addOrIncreaseCounterIfNecessary("fileName", "_", ("fileName",
* "fileName_1", "fileName_3") returns "fileName_2"
* addOrIncreaseCounterIfNecessary("fileName", "_", ("fileName_5",
* "fileName_1", "fileName_3") returns "fileName"
* addOrIncreaseCounterIfNecessary("fileName", "_", null ) returns
* "fileName"
*
* @param string
* @param token
* @param collection
* of strings
* @return string with added or increased counter if necessary
*/
public static String addOrIncreaseCounterIfNecessary(String string, String token, Collection collectionOfStrings) {
if (string == null) {
string = "";
}
if (collectionOfStrings == null) {
return string;
}
boolean stop = false;
do {
stop = false;
Iterator iterator = collectionOfStrings.iterator();
while (stop == false && iterator.hasNext()) {
String name = (String) iterator.next();
if (string.equals(name)) {
string = addOrIncreaseCounter(string, token);
stop = true;
}
}
}
while (stop == true);
return string;
}
/**
* Returns a string with an added or increased counter depending on the
* specified token. Null strings are handled like empty strings. Examples:
* addOrIncreaseCounter("fileName_13", "_") returns "fileName_14"
* addOrIncreaseCounter("fileName", "_") returns "fileName_1"
* addOrIncreaseCounter("fileName_12_13", "_") returns "fileName_12_14"
* addOrIncreaseCounter("", "_") returns "_1" addOrIncreaseCounter("", "")
* returns "1" addOrIncreaseCounter("fileName_13", "") returns
* "fileName_131" addOrIncreaseCounter("fileName_13", null) returns
* "fileName_131"
*
* @param string
* @param token
* @return string with added or increased counter.
*/
public static String addOrIncreaseCounter(String string, String token) {
if (string == null) {
string = "";
}
if (token == null) {
token = "";
}
// is there an existing counter?
int endIndex = string.lastIndexOf(token);
if (endIndex > -1) {
String number = string.substring(endIndex + token.length());
if (StringHandler.isNaturalNumber(number)) {
int counter = Integer.parseInt(number);
String newNumber = Integer.toString(++counter);
String newString = string.substring(0, endIndex);
StringBuffer buffer = new StringBuffer(newString);
buffer.append(token).append(newNumber);
return buffer.toString();
}
}
// string hasn't a counter add a counter
StringBuffer buffer = new StringBuffer(string);
buffer.append(token);
buffer.append("1");
return buffer.toString();
}
public static boolean isNumeric(String string) {
if (StringUtil.isEmpty(string))
return false;
for (int i = 0; i < string.length(); i++) {
char theChar = string.charAt(i);
if (!Character.isDigit(theChar)) {
return false;
}
}
return true;
}
/**
* Returns true if the specified string is a natural number. Zero is
* considered as a natural number. Examples: isNaturalNumber("-12") returns
* false isNaturalNumber("0") returns true; isNaturalNumber("12") returns
* true; isNaturalNumber("f1") returns false; isNaturalNumber("+12") returns
* false isNaturalNumber(null) returns false;
*
* @param string
* @return true if the specified string is a natural number else false
* @author thomas
*/
public static boolean isNaturalNumber(String string) {
if (string == null) {
return false;
}
int length = string.length();
if (length == 0) {
return false;
}
for (int i = 0; i < length; i++) {
char letter = string.charAt(i);
if (!Character.isDigit(letter)) {
return false;
}
}
return true;
}
/**
* Gets the words that are contained in a string corresponding to a list of
* allowed words. If the string contains a non allowed word an empty list
* ist returned. Example: list = "(" ")" "or" "xor" "A" "B" getElements("A
* or(B xor C)", list, true) returns "(" "A" "or" "(" "B" "xor" "C" ")"
*
* @param str
* @param allowedWords
* @param list
* of allowed words in str else null
* @author thomas
*/
public static List getElements(String string, Collection allowedWords) {
List result = new ArrayList();
// order of conditions
SortedSet orderedWords = new TreeSet(new Comparator() {
@Override
public int compare(Object first, Object second) {
int firstLength = ((String) first).length();
int secondLength = ((String) second).length();
if (firstLength < secondLength) {
return 1;
}
else if (firstLength > secondLength) {
return -1;
}
return ((Comparable) first).compareTo(second);
}
});
orderedWords.addAll(allowedWords);
String stringWithoutWhiteSpace = StringHandler.removeWhiteSpace(string);
int length = stringWithoutWhiteSpace.length();
boolean wordIsRecognized = true;
int index = 0;
while (index < length && wordIsRecognized) {
wordIsRecognized = false;
Iterator wordIterator = orderedWords.iterator();
while (wordIterator.hasNext() && (!wordIsRecognized)) {
String tempWord = (String) wordIterator.next();
if (stringWithoutWhiteSpace.startsWith(tempWord, index)) {
wordIsRecognized = true;
result.add(tempWord);
index += tempWord.length();
}
}
}
if (index != length) {
return null;
}
return result;
}
/**
* Compares two versions strings like "000.003.001" and "0.0044" in a fast
* way.
*
* @param version1
* @param version2
* @return Zero if the versions are the same, a value less than zero if the
* first version is less than the second version and value larger
* than zero if the first version is larger.
* @author thomas
*/
public static int compareVersions(String version1, String version2) {
int index1 = 0;
int index2 = 0;
int result = 0;
char c1;
char c2;
boolean firstDigitIsZero1 = true;
boolean firstDigitIsZero2 = true;
if (version1 == null) {
if (version2 == null) {
return 0;
}
return -1;
}
else if (version2 == null) {
return 1;
}
int versionLength1 = version1.length();
int versionLength2 = version2.length();
while (true) {
if (index1 == versionLength1) {
c1 = '.';
}
else {
c1 = version1.charAt(index1);
}
if (index2 == versionLength2) {
c2 = '.';
}
else {
c2 = version2.charAt(index2);
}
// one of the numbers starts with zero value
if (firstDigitIsZero1 || firstDigitIsZero2) {
if (firstDigitIsZero1 && c1 == '0' && c2 != '0') {
index1++;
firstDigitIsZero2 = false;
}
else if (firstDigitIsZero2 && c1 != '0' && c2 == '0') {
index2++;
firstDigitIsZero1 = false;
}
else if (c1 == '0' && c2 == '0') {
index1++;
index2++;
}
else {
firstDigitIsZero1 = false;
firstDigitIsZero2 = false;
}
}
// both numbers start with a non-zero value
else if (c1 == '.' && c2 != '.') {
// c2 is larger
return -1;
}
else if (c1 != '.' && c2 == '.') {
// c1 is larger
return 1;
}
else if (c1 == '.' && c2 == '.') {
// both numbers have the same length
// look at the result!
if (result != 0) {
return result;
}
// bad luck!
// go to the next number
// is there a next number?
if (index1 == versionLength1 || index2 == versionLength2) {
return result;
}
firstDigitIsZero1 = true;
firstDigitIsZero2 = true;
index1++;
index2++;
}
else {
// both characters are numbers
if (result == 0) {
result = c1 - c2;
}
index1++;
index2++;
}
}
}
/**
* Checks if the specified string contains the specified pattern. Example:
* replace("A cat is not a caterpillar", "ca") returns true
*
* @param string
* @param pattern
* @return true if the string contains the specified pattern else false.
* @author thomas
*/
public static boolean contains(String string, String pattern) {
return (string.indexOf(pattern) >= 0);
}
public static String[] TRANSLATED;
static {
TRANSLATED = new String[SUBSTITUTED_MAX - SUBSTITUTED_MIN + 1];
Arrays.fill(TRANSLATED, NO_LETTER_SUBSTITUTION);
for (int i = 0; i < SUBSTITUTION_GROUP.length; i++) {
int[] group = SUBSTITUTION_GROUP[i];
for (int j = 0; j < group.length; j++) {
int c = group[j];
TRANSLATED[c - SUBSTITUTED_MIN] = SUBSTITUTION[i];
}
}
}
/**
* Returns a suitable replacement for a character
* @param c the character to replace
* @param exceptions an array of exceptions e.g. {-,0,1,2,3,4,5,6,7,8,9}
*/
private static String translateNonRomanCharacter(char c, char[] exceptions) {
// get uni code number
int value = c;
// is c a "normal" letter?
if (('A' <= value && value <= 'Z') || ('a' <= value && value <= 'z') || (Arrays.binarySearch(exceptions,c) >= 0)){
return String.valueOf(c);
}
if ((value >= SUBSTITUTED_MIN) && (value <= SUBSTITUTED_MAX)) {
return TRANSLATED[value - SUBSTITUTED_MIN];
}
return NO_LETTER_SUBSTITUTION;
}
public static String shortenToLength(CharSequence sequence, int length) {
int tempLength = sequence.length();
if (tempLength <= length) {
return sequence.toString();
}
return sequence.subSequence(0, length).toString();
}
/**
* Returns a string or dash if there is no string. If the string is either
* null or an empty string a dash (-) is returned else it returns the input
* string str.
*
* @param str
* String to check
* @return String which is either a dash or the input str.
*/
public static String getStringOrDash(String str) {
if (str == null) {
return DASH;
}
if (str.equals(EMPTY_STRING)) {
return DASH;
}
return str;
}
/**
* Breaks down the URL string separated by the '/' charachter to an array.
* <br>
* For instance it breaks down the URL "/component/78909" to
* {"component","78909"}
*
* @return
*/
public static String[] breakDownURL(String urlString) {
// Performance optimization to handle the first 4 parameters without
// having to construct the Vector
String s1 = null;
String s2 = null;
String s3 = null;
String s4 = null;
List list = null;
StringTokenizer st = new StringTokenizer(urlString, SLASH);
int index = 0;
while (st.hasMoreTokens()) {
index++;
if (index == 1) {
s1 = st.nextToken();
}
else if (index == 2) {
s2 = st.nextToken();
}
else if (index == 3) {
s3 = st.nextToken();
}
else if (index == 4) {
s4 = st.nextToken();
}
else if (index == 5) {
list = new ArrayList();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(st.nextToken());
}
else if (index > 5) {
st.nextToken();
}
}
if (index == 1) {
String[] theReturn = { s1 };
return theReturn;
}
else if (index == 2) {
String[] theReturn = { s1, s2 };
return theReturn;
}
else if (index == 3) {
String[] theReturn = { s1, s2, s3 };
return theReturn;
}
else if (index == 4) {
String[] theReturn = { s1, s2, s3, s4 };
return theReturn;
}
else if (index > 4) {
String[] theReturn = (String[]) list.toArray(new String[0]);
return theReturn;
}
return null;
}
public static String firstCharacterToUpperCase(String string) {
if (string.length() == 1) {
return string.toUpperCase();
}
else if (string.length() > 1) {
return string.substring(0, 1).toUpperCase().concat(string.substring(1));
}
else {
return string;
}
}
public static String firstCharacterToUpperCaseRestToLowerCase(String string) {
return StringHandler.firstCharacterToUpperCase(string.toLowerCase());
}
private static char[] allowedcharacters={'-','0','1','2','3','4','5','6','7','8','9'};
/**
* Parses the inputString so that it has a "URL friendly" format. i.e. only
* latin characters in lowercase without special characters. <br>
* e.g. the inputString "Fréttir á Forsíðu" becomes
* "frettiraforsidu"
*
* @param complexString
* @return
*/
public static String convertToUrlFriendly(String complexString) {
String noWhitespace = removeWhiteSpace(complexString);
String nonLatin = stripNonRomanCharacters(noWhitespace,allowedcharacters);
String lowercase = nonLatin.toLowerCase();
return lowercase;
}
/**
* Parses the passed inputString so that it removes all occurences of the slash ('/') character
* where it is twice or more in a row in a string.<br>
* e.g. the inputString '//myurl//mypage//' becomes '/myurl/mypage/'
* @param input
* @return
*/
public static String removeMultipleSlashes(String inputString){
char[] characters = inputString.toCharArray();
StringBuffer ret = new StringBuffer();
boolean lastWasSlash=false;
for (int i = 0; i < characters.length; i++) {
char c = characters[i];
if(c=='/'){
if(lastWasSlash){
lastWasSlash=true;
//skip this character
}
else{
lastWasSlash=true;
ret.append(c);
}
}
else{
if(lastWasSlash){
lastWasSlash=false;
}
ret.append(c);
}
}
return ret.toString();
}
/**
* Uses a regular expression to remove all html tags from the string. Code found at http://www.tivocommunity.com/tivo-vb/archive/index.php/t-229458.html
* @param htmlString
* @return
*/
public static String removeHtmlTagsFromString(String htmlString){
return htmlString.replaceAll("\\<.*?\\>","");
}
/**
* Checks if value is represented in hexidecimal notation
* @param value
* @return true || false
*/
public static boolean isHexidecimalValue(String value) {
if (-2 == getNotHexValueIndexInHexValue(value)) {
return true;
}
return false;
}
/**
* Returns the first index of not hexidecimal letter in provided String
* @param value
* @return -2 - didn't find incorrext letter, -1 - error, index
*/
public static int getNotHexValueIndexInHexValue(String value) {
if (value == null) {
return -1; // Error
}
value = value.trim();
if (value.startsWith(CoreConstants.HASH)) {
value = value.substring(value.indexOf(CoreConstants.HASH));
}
if (value.endsWith(CoreConstants.SEMICOLON)) {
value = value.substring(0, value.lastIndexOf(CoreConstants.SEMICOLON));
}
if (value.length() == 3 || value.length() == 6) {
for (int i = 0; i < value.length(); i++) {
if (!Character.isDigit(value.charAt(i))) {
if (!CoreConstants.HEXIDECIMAL_LETTERS.contains(String.valueOf(value.charAt(i)))) {
return i; // Error - returning index
}
}
}
return -2; // OK
}
return -1; // Error
}
public static String removeCharacters(String value, String whatToRemove, String whatToPlace) {
if (value == null || whatToRemove == null || whatToPlace == null) {
return null;
}
value = value.trim();
while (value.indexOf(whatToRemove) != -1) {
value = value.replace(whatToRemove, whatToPlace);
}
return value;
}
/**
* Converts a wildcard expression to a regular expression, that is
* "*" is replaced by ".*" and
* "?" is replaced by "."
* Protects existing dots in the wildcard expressions.
*
* If the specified wildcardExpression is null or empty the specified wildcardExpression is simply returned.
*
* Examples: "hello.c?s*" returns "hello\.c.s.*"
*
* Typical invocation sequence:
* String regex = StringHandler.convertWildcardExpressionToRegularExpression("H?llo W*");
* Pattern pattern = Pattern.compile(regex);
* Matcher matcher = pattern.matches("Hello world");
* boolean b = matcher.matches();
*
* @param wildcardExpression
* @return regular expression
*/
public static String convertWildcardExpressionToRegularExpression(String wildcardExpression) {
if (StringHandler.isEmpty(wildcardExpression)) {
return wildcardExpression;
}
String regularExpression = wildcardExpression.replace(".", "\\.");
regularExpression = regularExpression.replace('?', '.');
regularExpression = regularExpression.replace("*", ".*");
return regularExpression;
}
public static String removeAbsoluteReferencies(String text) {
if (text == null) {
return null;
}
StringBuffer replaceBuffer = new StringBuffer(text);
List<Pattern> patterns = new ArrayList<Pattern>();
Pattern p1 = Pattern.compile("(<a[^>]+href=\")([^#][^\"]+)([^>]+>)", Pattern.CASE_INSENSITIVE);
Pattern p2 = Pattern.compile("(<img[^>]+src=\")([^#][^\"]+)([^>]+>)", Pattern.CASE_INSENSITIVE);
patterns.add(p1);
patterns.add(p2);
StringBuffer outString = null;
IWContext iwc = CoreUtil.getIWContext();
String serverName = null;
if (iwc != null) {
serverName = iwc.getServerName();
}
if (serverName == null) {
return text;
}
for (int i = 0; i < patterns.size(); i++) {
Pattern p = patterns.get(i);
Matcher m = p.matcher(replaceBuffer);
outString = new StringBuffer();
while (m.find()) {
String url = m.group(2);
if (url.startsWith("http") && url.indexOf(serverName) > 0) {
url = url.substring(url.indexOf("//")+2);
url = url.substring(url.indexOf("/"));
m.appendReplacement(outString,"$1"+url+"$3");
}
}
m.appendTail(outString);
replaceBuffer=new StringBuffer(outString.toString());
}
text = replaceBuffer.toString();
return text;
}
public static String removeAbsoluteReference(String serverName, String link) {
if (link == null) {
return null;
}
if (serverName == null) {
return link;
}
if (link.indexOf(serverName) == -1) {
return link;
}
link = link.toLowerCase();
// Throwing away server name from link
int serverNameStart = link.indexOf(serverName);
if (serverNameStart > 0) {
int serverNameEnd = serverNameStart + serverName.length();
link = link.substring(serverNameEnd);
}
// Throwing away port number from link
if (link.startsWith(":")) {
link = link.substring(1);
boolean portNumber = true;
try {
while (link.length() > 0 && portNumber && Integer.valueOf(link.substring(0, 1)) != null) {
link = link.substring(1);
}
} catch (NumberFormatException e) {
portNumber = false;
}
}
return link;
}
public static String getContentFromStream(InputStream stream) {
try {
return getContentFromInputStream(stream);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getContentFromInputStream(InputStream stream) throws Exception {
if (stream == null) {
return null;
}
BufferedReader br = new BufferedReader(new InputStreamReader(stream, Charset.forName(CoreConstants.ENCODING_UTF8)));
try {
return getContentFromReader(br);
} finally {
IOUtil.close(stream);
}
}
public static String getContentFromReader(Reader reader) throws Exception {
if (reader == null) {
return null;
}
BufferedReader bReader = null;
if (reader instanceof BufferedReader) {
bReader = (BufferedReader) reader;
} else {
bReader = new BufferedReader(reader);
}
StringBuffer sb = new StringBuffer();
String line = null;
try {
while ((line = bReader.readLine()) != null) {
sb.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
IOUtil.closeReader(reader);
IOUtil.closeReader(bReader);
}
return sb.toString();
}
/**
* Returns UTF-8 encoded stream
* @param content
* @return
* @throws Exception
*/
public static InputStream getStreamFromString(String content) throws Exception {
if (content == null) {
return null;
}
return new BufferedInputStream(new ByteArrayInputStream(content.getBytes(CoreConstants.ENCODING_UTF8)));
}
}