/*******************************************************************************
* Copyright (c) 2001, 2006 IBM Corporation and others. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: IBM Corporation - initial API and implementation Jens
* Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org2.eclipse.php.util;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jface.internal.text.html.HTMLPrinter;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
@SuppressWarnings({"restriction", "unchecked", "rawtypes"})
public class StringUtils {
protected static final String AMPERSTAND = "&"; //$NON-NLS-1$
protected static final String AMPERSTAND_ENTITY = "&&;"; //$NON-NLS-1$
protected static final String CARRIAGE_RETURN = "\r"; //$NON-NLS-1$
protected static final String CARRIAGE_RETURN_ENTITY = "\\r"; //$NON-NLS-1$
protected static final String CR = "\r"; //$NON-NLS-1$
protected static final String CRLF = "\r\n"; //$NON-NLS-1$
protected static final String DELIMITERS = " \t\n\r\f"; //$NON-NLS-1$
protected static final String DOUBLE_QUOTE = "\""; //$NON-NLS-1$
protected static final char DOUBLE_QUOTE_CHAR = '\"';
protected static final String DOUBLE_QUOTE_ENTITY = """; //$NON-NLS-1$
protected static final String EQUAL_SIGN = "="; //$NON-NLS-1$
protected static final String EQUAL_SIGN_ENTITY = "="; //$NON-NLS-1$
private static final String FALSE = "false"; //$NON-NLS-1$
protected static final String GREATER_THAN = ">"; //$NON-NLS-1$
protected static final String GREATER_THAN_ENTITY = ">"; //$NON-NLS-1$
protected static final String LESS_THAN = "<"; //$NON-NLS-1$
protected static final String LESS_THAN_ENTITY = "<"; //$NON-NLS-1$
protected static final String LF = "\n"; //$NON-NLS-1$
protected static final String LINE_FEED = "\n"; //$NON-NLS-1$
protected static final String LINE_FEED_ENTITY = "\\n"; //$NON-NLS-1$
protected static final String LINE_FEED_TAG = "<dl>"; //$NON-NLS-1$
protected static final String LINE_TAB = "\t"; //$NON-NLS-1$
protected static final String LINE_TAB_ENTITY = "\\t"; //$NON-NLS-1$
protected static final String LINE_TAB_TAG = "<dd>"; //$NON-NLS-1$
protected static final String SINGLE_QUOTE = "'"; //$NON-NLS-1$
protected static final char SINGLE_QUOTE_CHAR = '\'';
protected static final String SINGLE_QUOTE_ENTITY = "'"; //$NON-NLS-1$
protected static final String SPACE = " "; //$NON-NLS-1$
protected static final String SPACE_ENTITY = " "; //$NON-NLS-1$
private static final String TRUE = "true"; //$NON-NLS-1$
/**
* Append appendString to the end of aString only if aString does not end
* with the insertString.
*/
public static String appendIfNotEndWith(final String aString, final String appendString) {
if (aString != null && appendString != null)
if (aString.endsWith(appendString))
return aString;
else
return aString + appendString;
else
return aString;
}
/**
* Breaks out space-separated words into an array of words. For example:
* <code>"no comment"</code> into an array <code>a[0]="no"</code> and
* <code>a[1]= "comment"</code>.
*
* @param value
* the string to be converted
* @return the list of words
*/
public static String[] asArray(final String value) {
ArrayList list = new ArrayList();
StringTokenizer stok = new StringTokenizer(value);
while (stok.hasMoreTokens()) {
list.add(stok.nextToken());
}
String result[] = new String[list.size()];
list.toArray(result);
return result;
}
/**
* Breaks out delim-separated words into an array of words. For example:
* <code>"no comment"</code> into an array <code>a[0]="no"</code> and
* <code>a[1]= "comment"</code>.
*
* @param value
* the string to be converted
* @return the list of words
*/
public static String[] asArray(final String value, final String delim) {
return asArray(value, delim, false);
}
/**
* Breaks out delim-separated words into an array of words. For example:
* <code>"no comment"</code> into an array <code>a[0]="no"</code> and
* <code>a[1]= "comment"</code>.
*
* @param value
* the string to be converted
* @return the list of words
*/
public static String[] asArray(final String value, final String delim, final boolean returnTokens) {
ArrayList list = new ArrayList();
StringTokenizer stok = new StringTokenizer(value, delim, returnTokens);
while (stok.hasMoreTokens()) {
list.add(stok.nextToken());
}
String result[] = new String[list.size()];
list.toArray(result);
return result;
}
/**
* Breaks out delim-separated words into an array of words. For example:
* <code>"abc,,def"</code> into an array <code>a[0]="abc"</code>,
* <code>a[1]=null</code>, and <code>a[2]= "def"</code> where "," is the
* delim.
*
* @param value
* the string to be converted
* @return the list of words
*/
public static String[] asFixedArray(final String value, final String delim) {
String array[] = asArray(value, delim, true);
int arrayLength = array.length;
boolean stringFound = false;
ArrayList list = new ArrayList();
for (int i = 0; i < arrayLength; i++) {
String token = array[i];
if (token.compareTo(delim) == 0) {
if (!stringFound) {
list.add(null);
}
stringFound = false;
} else {
list.add(token);
stringFound = true;
}
}
// add one more null if last token is the delim
if (!stringFound) {
list.add(null);
}
String result[] = new String[list.size()];
list.toArray(result);
return result;
}
public static String chop(final String source) {
return chop(source, "/"); //$NON-NLS-1$
}
public static String chop(final String source, final String delimiter) {
return source.substring(0, source.lastIndexOf(delimiter));
}
public static boolean contains(final String[] arrayOfStrings, final String needle, final boolean caseSensitive) {
boolean result = false;
if (needle == null)
return false;
if (arrayOfStrings == null)
return false;
if (caseSensitive) {
for (String arrayOfString : arrayOfStrings) {
if (needle.equals(arrayOfString)) {
result = true;
break;
}
}
} else {
for (String arrayOfString : arrayOfStrings) {
if (needle.equalsIgnoreCase(arrayOfString)) {
result = true;
break;
}
}
}
return result;
}
public static boolean containsLetters(final String fullValue) {
if (fullValue == null || fullValue.length() == 0)
return false;
char[] chars = fullValue.toCharArray();
for (int i = 0; i < fullValue.length(); i++)
if (Character.isLetter(chars[i]))
return true;
return false;
}
public static boolean containsLineDelimiter(final String aString) {
return indexOfLineDelimiter(aString) != -1;
}
public static String convertLineDelimiters(final String allText, String lineDelimiterToUse)
throws BadLocationException {
IDocument tempDoc = new Document(allText);
if (lineDelimiterToUse == null) {
lineDelimiterToUse = System.getProperty("line.separator"); //$NON-NLS-1$
}
String newText = ""; //$NON-NLS-1$
int lineCount = tempDoc.getNumberOfLines();
for (int i = 0; i < lineCount; i++) {
org.eclipse.jface.text.IRegion lineInfo = tempDoc.getLineInformation(i);
int lineStartOffset = lineInfo.getOffset();
int lineLength = lineInfo.getLength();
int lineEndOffset = lineStartOffset + lineLength;
newText += allText.substring(lineStartOffset, lineEndOffset);
if (i < lineCount - 1 && tempDoc.getLineDelimiter(i) != null) {
newText += lineDelimiterToUse;
}
}
return newText;
}
/**
* Replaces all instances of special HTML characters with the appropriate
* HTML entity equivalent. WARNING only use this method for strings that
* dont already have HTML-specific items such as tags and entities.
*
* @param String
* content String to convert
*
* @return String the converted string
* @see HTMLPrinter#convertToHTMLContent(String content)
*/
public static String convertToHTMLContent(String content) {
content = replace(content, AMPERSTAND, AMPERSTAND_ENTITY);
content = replace(content, LESS_THAN, LESS_THAN_ENTITY);
content = replace(content, GREATER_THAN, GREATER_THAN_ENTITY);
content = replace(content, LINE_FEED, LINE_FEED_TAG);
content = replace(content, LINE_TAB, LINE_TAB_TAG);
content = replace(content, SINGLE_QUOTE, SINGLE_QUOTE_ENTITY);
content = replace(content, DOUBLE_QUOTE, DOUBLE_QUOTE_ENTITY);
content = replace(content, SPACE + SPACE, SPACE_ENTITY + SPACE_ENTITY); // replacing
// every
// space
// would
// be
// too
// much
return content;
}
/**
* Converts a string into a form that will not conflict with saving it into
* an INI file.
*/
public static String escape(final String normalString) {
if (normalString == null)
return null;
StringBuffer escapedBuffer = new StringBuffer();
StringTokenizer toker = new StringTokenizer(normalString, EQUAL_SIGN + LINE_FEED + CARRIAGE_RETURN + LINE_TAB,
true);
String chunk = null;
while (toker.hasMoreTokens()) {
chunk = toker.nextToken();
if (chunk.equals(EQUAL_SIGN)) {
escapedBuffer.append(EQUAL_SIGN_ENTITY);
} else if (chunk.equals(LINE_FEED)) {
escapedBuffer.append(LINE_FEED_ENTITY);
} else if (chunk.equals(CARRIAGE_RETURN)) {
escapedBuffer.append(CARRIAGE_RETURN_ENTITY);
} else if (chunk.equals(LINE_TAB)) {
escapedBuffer.append(LINE_TAB_ENTITY);
} else {
escapedBuffer.append(chunk);
}
}
return escapedBuffer.toString();
}
/**
* Returns the first line of the given text without a trailing delimiter.
*
* @param text
* @return
*/
public static String firstLineOf(final String text) {
if (text == null || text.length() < 1)
return text;
IDocument doc = new Document(text);
try {
int lineNumber = doc.getLineOfOffset(0);
IRegion line = doc.getLineInformation(lineNumber);
return doc.get(line.getOffset(), line.getLength());
} catch (BadLocationException e) {
// do nothing
}
return text;
}
public static int indexOfLastLineDelimiter(final String aString) {
return indexOfLastLineDelimiter(aString, aString.length());
}
public static int indexOfLastLineDelimiter(final String aString, final int offset) {
int index = -1;
if (aString != null && aString.length() > 0) {
index = aString.lastIndexOf(CRLF, offset);
if (index == -1) {
index = aString.lastIndexOf(CR, offset);
if (index == -1) {
index = aString.lastIndexOf(LF, offset);
}
}
}
return index;
}
public static int indexOfLineDelimiter(final String aString) {
return indexOfLineDelimiter(aString, 0);
}
public static int indexOfLineDelimiter(final String aString, final int offset) {
int index = -1;
if (aString != null && aString.length() > 0) {
index = aString.indexOf(CRLF, offset);
if (index == -1) {
index = aString.indexOf(CR, offset);
if (index == -1) {
index = aString.indexOf(LF, offset);
}
}
}
return index;
}
public static int indexOfNonblank(final String aString) {
return indexOfNonblank(aString, 0);
}
public static int indexOfNonblank(final String aString, final int offset) {
int index = -1;
if (aString != null && aString.length() > 0) {
for (int i = offset; i < aString.length(); i++) {
if (DELIMITERS.indexOf(aString.substring(i, i + 1)) == -1) {
index = i;
break;
}
}
}
return index;
}
/**
* Insert insertString to the beginning of aString only if aString does not
* start with the insertString.
*/
public static String insertIfNotStartWith(final String aString, final String insertString) {
if (aString != null && insertString != null)
if (aString.startsWith(insertString))
return aString;
else
return insertString + aString;
else
return aString;
}
public static boolean isQuoted(final String string) {
if (string == null || string.length() < 2)
return false;
int lastIndex = string.length() - 1;
char firstChar = string.charAt(0);
char lastChar = string.charAt(lastIndex);
return firstChar == SINGLE_QUOTE_CHAR && lastChar == SINGLE_QUOTE_CHAR || firstChar == DOUBLE_QUOTE_CHAR
&& lastChar == DOUBLE_QUOTE_CHAR;
}
/**
* Unit tests.
*
* @param args
* java.lang.String[]
*/
public static void main(final String[] args) {
// testPaste();
testStripNonLetterDigits();
}
/*
* Returns the merged form of both strings
*/
public static String merge(final String newStart, final String newEnd) {
String[] regions = overlapRegions(newStart, newEnd);
return regions[0] + regions[1] + regions[2];
}
public static int occurrencesOf(final String searchString, final char targetChar) {
int result = 0;
int len = searchString.length();
for (int i = 0; i < len; i++) {
if (targetChar == searchString.charAt(i)) {
result++;
}
}
return result;
}
/**
*
* @return java.lang.String[]
* @param start
* java.lang.String
* @param end
* java.lang.String
*
* Returns a 3 String array containing unique text from the
* start, duplicated text that overlaps the start and end, and
* the unique text from the end.
*/
private static String[] overlapRegions(final String start, final String end) {
String[] results = null;
if (start != null && end == null) {
results = new String[] { start, "", "" }; //$NON-NLS-2$//$NON-NLS-1$
} else if (start == null && end != null) {
results = new String[] { "", "", end }; //$NON-NLS-2$//$NON-NLS-1$
} else if (start == null && end == null) {
results = new String[] { "", "", "" }; //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
} else if (start != null && end != null) {
int startLength = start.length();
int endLength = end.length();
if (startLength == 0 || endLength == 0) {
results = new String[] { "", "", "" }; //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
} else {
results = new String[3];
String testStart = ""; //$NON-NLS-1$
String testEnd = ""; //$NON-NLS-1$
int mergeLength = Math.min(startLength, endLength);
boolean finished = false;
while (mergeLength > 0 && !finished) {
testStart = start.substring(startLength - mergeLength);
testEnd = end.substring(0, mergeLength);
// case sensitive
if (testStart.equals(testEnd)) {
finished = true;
results[0] = start.substring(0, startLength - mergeLength);
results[1] = start.substring(startLength - mergeLength);
results[2] = end.substring(mergeLength);
}
mergeLength--;
}
if (!finished) {
results[0] = start;
results[1] = ""; //$NON-NLS-1$
results[2] = end;
}
}
}
return results;
}
/**
* Packs an array of Strings into a single comma delimited String.
*
* @param strings
* @return
* @todo Generated comment
*/
public static String pack(final String[] strings) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < strings.length; i++) {
buf.append(StringUtils.replace(strings[i], ",", ",")); //$NON-NLS-1$ //$NON-NLS-2$
if (i < strings.length - 1) {
buf.append(","); //$NON-NLS-1$
}
}
return buf.toString();
}
/*
* Pastes the new text into the old at the start position, replacing text
* implied by length.
*/
public static String paste(final String oldText, final String newText, final int start, final int length) {
String result = null;
StringBuffer sb = new StringBuffer();
int startIndex = start;
int endIndex = start + length;
if (startIndex > oldText.length()) {
startIndex = oldText.length();
}
sb.append(oldText.substring(0, startIndex));
// null or empty new text accompliches a delete
if (newText != null) {
sb.append(newText);
}
if (endIndex < oldText.length()) {
sb.append(oldText.substring(endIndex));
}
result = sb.toString();
return result;
}
/**
* Replace matching literal portions of a string with another string
*/
public static String replace(final String aString, final String source, final String target) {
if (aString == null)
return null;
String normalString = ""; //$NON-NLS-1$
int length = aString.length();
int position = 0;
int previous = 0;
int spacer = source.length();
while (position + spacer - 1 < length && aString.indexOf(source, position) > -1) {
position = aString.indexOf(source, previous);
normalString = normalString + aString.substring(previous, position) + target;
position += spacer;
previous = position;
}
normalString = normalString + aString.substring(position, aString.length());
return normalString;
}
/**
* Restore the entity references for markup delimiters in text where they
* have been replaced by the proper Unicode values through a DOM text
* parser.
*/
public static String restoreMarkers(final String text) {
String content = text;
content = replace(content, AMPERSTAND, AMPERSTAND_ENTITY);
content = replace(content, LESS_THAN, LESS_THAN_ENTITY);
content = replace(content, GREATER_THAN, GREATER_THAN_ENTITY);
return content;
}
/**
* Removes extra whitespace characters and quotes
*/
public static String strip(final String quotedString) {
if (quotedString == null || quotedString.length() == 0)
return quotedString;
String trimmed = quotedString.trim();
if (trimmed.length() < 2)
return quotedString;
char first = trimmed.charAt(0);
char nextToLast = trimmed.charAt(trimmed.length() - 2);
char last = trimmed.charAt(trimmed.length() - 1);
if (first == '\"' && last == '\"' && nextToLast != '\\' || first == '\'' && last == '\'' && nextToLast != '\\')
return trimmed.substring(1, trimmed.length() - 1);
return trimmed;
}
/**
* This method strips anything from the beginning and end of a string that
* is not a letter or digit. It is used by some encoding detectors to come
* up with the encoding name from illformed input (e.g in <?xml
* encoding="abc?> -- where final quote is left off, the '>' is returned
* with the rest of the attribute value 'abc').
*/
public static String stripNonLetterDigits(final String fullValue) {
if (fullValue == null || fullValue.length() == 0)
return fullValue;
int fullValueLength = fullValue.length();
int firstPos = 0;
while (firstPos < fullValueLength && !Character.isLetterOrDigit(fullValue.charAt(firstPos))) {
firstPos++;
}
int lastPos = fullValueLength - 1;
while (lastPos > firstPos && !Character.isLetterOrDigit(fullValue.charAt(lastPos))) {
lastPos--;
}
String result = fullValue;
if (firstPos != 0 || lastPos != fullValueLength) {
result = fullValue.substring(firstPos, lastPos + 1);
}
return result;
}
/**
* Similar to strip, except quotes don't need to match such as "UTF' is
* still stripped of both quotes. (Plus, this one does not detect escaped
* quotes)
*/
public static String stripQuotes(final String quotedValue) {
if (quotedValue == null)
return null;
// normally will never have leading or trailing blanks,
// but if it does, we'll do lenient interpretation
return stripQuotesLeaveInsideSpace(quotedValue).trim();
}
/**
* Like strip quotes, except leaves the start and end space inside the
* quotes.
*
* @param quotedValue
* @return
*/
public static String stripQuotesLeaveInsideSpace(final String quotedValue) {
if (quotedValue == null)
return null;
// nomally will never have leading or trailing blanks ... but just in
// case.
String result = quotedValue.trim();
int len = result.length();
if (len > 0) {
char firstChar = result.charAt(0);
if (firstChar == SINGLE_QUOTE_CHAR || firstChar == DOUBLE_QUOTE_CHAR) {
result = result.substring(1, len);
}
len = result.length();
if (len > 0) {
char lastChar = result.charAt(len - 1);
if (lastChar == SINGLE_QUOTE_CHAR || lastChar == DOUBLE_QUOTE_CHAR) {
result = result.substring(0, len - 1);
}
}
}
return result;
}
public static void testPaste() {
String testString = "The quick brown fox ..."; //$NON-NLS-1$
System.out.println(paste(testString, null, 4, 5));
System.out.println(paste(testString, null, 4, 6));
System.out.println(paste(testString, "", 4, 6)); //$NON-NLS-1$
System.out.println(paste(testString, "fast", 4, 6)); //$NON-NLS-1$
System.out.println(paste(testString, "fast ", 4, 6)); //$NON-NLS-1$
System.out.println(paste(testString, "But ", 0, 0)); //$NON-NLS-1$
System.out.println(paste("", "burp", 4, 6)); //$NON-NLS-2$//$NON-NLS-1$
}
public static void testStripNonLetterDigits() {
String testString = "abc"; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = ""; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = "\"abc\""; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = "\"ab-c1?"; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = "+++"; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = "abc="; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
testString = "abc "; //$NON-NLS-1$
System.out.println(testString + " -->" + stripNonLetterDigits(testString) + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
}
public static String toString(final boolean booleanValue) {
if (booleanValue)
return TRUE;
else
return FALSE;
}
/**
* Remove "escaped" chars from a string.
*/
public static String unescape(final String aString) {
if (aString == null)
return null;
String normalString = replace(aString, EQUAL_SIGN_ENTITY, EQUAL_SIGN);
normalString = replace(normalString, LINE_FEED_ENTITY, LINE_FEED);
normalString = replace(normalString, CARRIAGE_RETURN_ENTITY, CARRIAGE_RETURN);
normalString = replace(normalString, LINE_TAB_ENTITY, LINE_TAB);
return normalString;
}
public static String uniqueEndOf(final String newStart, final String newEnd) {
String[] regions = overlapRegions(newStart, newEnd);
return regions[2];
}
/**
* Unpacks a comma delimited String into an array of Strings.
*
* @param s
* @return
* @todo Generated comment
*/
public static String[] unpack(final String s) {
if (s == null)
return new String[0];
StringTokenizer toker = new StringTokenizer(s, ","); //$NON-NLS-1$
List list = new ArrayList();
while (toker.hasMoreTokens()) {
// since we're separating the values with ',', escape ',' in the
// values
list.add(StringUtils.replace(toker.nextToken(), ",", ",").trim()); //$NON-NLS-1$ //$NON-NLS-2$
}
return (String[]) list.toArray(new String[0]);
}
/**
* StringUtils constructor comment.
*/
private StringUtils() {
super();
}
public static String join(String joinStr, String[] strings)
{
StringBuilder builder = new StringBuilder();
for (String str : strings)
{
builder.append(str);
builder.append(joinStr);
}
if (builder.length() > 0)
{
int end = builder.length() - 1;
builder.delete(end - joinStr.length(), end);
}
return builder.toString();
}
}