/*******************************************************************************
* Copyright (c) 2007 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial implementation
*******************************************************************************/
package melnorme.utilbox.misc;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import melnorme.utilbox.collections.ArrayList2;
/**
* Miscelleanous String utilities
*/
public class StringUtil {
public static final Charset ASCII = Charset.forName("ASCII");
public static final Charset UTF8 = Charset.forName("UTF-8");
public static final Charset UTF16 = Charset.forName("UTF-16");
public static String asString(Object obj) {
return obj == null ? null : obj.toString();
}
/** @return "" if given string is null, or the given string otherwise. */
public static String nullAsEmpty(String string) {
return string == null ? "" : string;
}
public static String nullAsEmpty(Object obj) {
if(obj == null)
return "";
return obj.toString();
}
/** @return null if given string is empty, or the given string otherwise. */
public static String emptyAsNull(String string) {
if(string != null && string.isEmpty())
return null;
return string;
}
/** @return a String produced from the given coll with the given separator String,
* using the elements's toString() method. */
public static String toString(Iterable<?> iterable, String separator) {
return toString(iterable, separator, null);
}
public static String collToString(Iterable<?> coll, String separator) {
return iterToString(coll, separator, null);
}
public static <T> String iterToString(Iterable<T> iterable, String separator,
Function<? super T, String> toStringFn) {
return toString(iterable, separator, toStringFn);
}
public static <T> String toString(Iterable<T> iterable, String separator, Function<? super T, String> toStringFn) {
return iteratorToString(iterable.iterator(), separator, toStringFn);
}
private static <T> String iteratorToString(Iterator<T> iter, String sep, Function<? super T, String> toStringFn) {
StringBuilder sb = new StringBuilder();
while(iter.hasNext()) {
T element = iter.next();
sb.append(toStringFn == null ? element.toString() : toStringFn.apply(element));
if(iter.hasNext()) {
sb.append(sep);
}
}
return sb.toString();
}
// This helper function is not used in code, but rather for Eclipse IDE debug detail formatters
@SuppressWarnings("unused")
private static <T> String debug_collToString(Collection<T> coll) {
// java.util.Collection<?> coll = this;
java.lang.StringBuilder sb = new java.lang.StringBuilder();
boolean first = true;
for(Object element : coll){
if(!first)
sb.append("\n");
first = false;
String elementString = element == null ? "null" : element.toString();
sb.append(elementString.replace("\n", "¶"));
}
return sb.toString();
}
@SuppressWarnings({ "unused", "rawtypes" })
private static String debug_mapToString(Map<?, ?> map) {
// java.util.Map<?, ?> map = this;
java.lang.StringBuilder sb = new java.lang.StringBuilder();
boolean first = true;
for(java.util.Map.Entry entry : map.entrySet()){
if(!first)
sb.append("\n");
first = false;
sb.append(entry.getKey());
sb.append("►");
Object element = entry.getValue();
String elementString = element == null ? "null" : element.toString();
sb.append(elementString.replace("\n", "¶"));
}
return sb.toString();
}
/** @return a String from the given coll with a given separator String. */
public static String collToString(Object[] coll, String sep) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for(Object item : coll){
if(!first)
sb.append(sep);
first = false;
sb.append(item.toString());
}
return sb.toString();
}
/** Creates a String array where each element is the to toString()
* of each element of the given collection. */
public static String[] collToStringArray(List<?> coll) {
if(coll == null)
return new String[0];
String[] strs = new String[coll.size()];
Iterator<?> iter = coll.iterator();
for (int i = 0; i < strs.length; i++) {
strs[i] = iter.next().toString();
}
return strs;
}
/* ----------------- queries ----------------- */
/** @return the number of ocurrences of given character in given string */
public static int occurrenceCount(String string, char character) {
int count = 0;
for(int fromIndex = 0; true ; count++, fromIndex++ ) {
fromIndex = string.indexOf(character, fromIndex);
if(fromIndex == -1) {
return count;
}
}
}
/* ----------------- modifications ----------------- */
/** @return str with the given range (repOffset and repLen) substituted for repStr. */
public static String replaceStr(String str, int repOffset, int repLen, String repStr) {
return str.substring(0, repOffset) + repStr + str.substring(repOffset + repLen, str.length());
}
/**
* @return replace all occurrences of given matchStr with repStr, in given string.
* Similar to {@link String#replaceAll(String, String)} but doesn't use regexps,
* therefore doesn't require any quoting.
*/
public static String replaceAll(String string, String matchStr, String repStr) {
StringBuilder sb = new StringBuilder();
int startIx = 0;
while(true) {
int matchIx = string.indexOf(matchStr, startIx);
if(matchIx == -1) {
sb.append(string, startIx, string.length());
break;
}
sb.append(string, startIx, matchIx);
sb.append(repStr);
startIx = matchIx + matchStr.length();
}
return sb.toString();
}
/** Replace str with strRep in the given strb StringBuilder, if str occurs.
* @return true if str occurs in strb. */
public static boolean replace(StringBuilder strb, String str, String repStr) {
int ix = strb.indexOf(str);
if(ix != -1) {
strb.replace(ix, ix + str.length(), repStr);
return true;
}
return false;
}
/** @return a substring of given string up until the start of the first occurrence of given match,
* or the whole string if no match is found. */
public static String substringUntilMatch(String string, String match) {
int index = string.indexOf(match);
return (index == -1) ? string : string.substring(0, index);
}
/** @return a substring of given string up until the start of the first occurrence of given match,
* or null if no match is found. */
public static String segmentUntilMatch(String string, String match) {
int index = string.indexOf(match);
return (index == -1) ? null : string.substring(0, index);
}
/** @return a substring of given string starting from the end of the first occurrence of given match,
* or the whole string if no match is found. */
public static String substringAfterMatch(String string, String match) {
int index = string.indexOf(match);
return (index == -1) ? string : string.substring(index + match.length());
}
/** @return a substring of given string starting from the end of the first occurrence of given match,
* or null if no match is found. */
public static String segmentAfterMatch(String string, String match) {
int index = string.indexOf(match);
return (index == -1) ? null : string.substring(index + match.length());
}
/** @return a substring of given string up until the start of the last occurrence of given match,
* or the whole string if no match is found. */
public static String substringUntilLastMatch(String string, String match) {
int index = string.lastIndexOf(match);
return (index == -1) ? string : string.substring(0, index);
}
/** @return a substring of given string up until the start of the last occurrence of given match,
* or null if no match is found. */
public static String segmentUntilLastMatch(String string, String match) {
int index = string.lastIndexOf(match);
return (index == -1) ? null : string.substring(0, index);
}
/** @return a substring of given string starting from the end of the last occurrence of given match,
* or the whole string if no match is found. */
public static String substringAfterLastMatch(String string, String match) {
int index = string.lastIndexOf(match);
return (index == -1) ? string : string.substring(index + match.length());
}
/** @return a substring of given string starting from the end of the last occurrence of given match,
* or null if no match is found. */
public static String segmentAfterLastMatch(String string, String match) {
int index = string.lastIndexOf(match);
return (index == -1) ? null : string.substring(index + match.length());
}
/** @return A substring of given string starting from the first occurrence of given match.
* Empty string if no match is found. */
public static String substringFromMatch(char match, String string) {
int indexOf = string.indexOf(match);
return indexOf == -1 ? "" : string.substring(indexOf);
}
/** @return A substring of given string starting from the first occurrence of given match.
* Empty string if no match is found. */
public static String substringFromMatch(String match, String string) {
int indexOf = string.indexOf(match);
return indexOf == -1 ? "" : string.substring(indexOf);
}
public static String trimStart(String string, String startMatch) {
return removeStart(startMatch, string);
}
/** If given string starts with given startMatch, remove that from string.
* @return the result. */
public static String removeStart(String startMatch, String string) {
if(string.startsWith(startMatch)) {
return string.substring(startMatch.length());
}
return string;
}
/** If given string ends with given endMatch, trim that from string.
* @return the result. */
public static String trimEnd(String string, String endMatch) {
if(string.endsWith(endMatch)) {
return string.substring(0, string.length() - endMatch.length());
}
return string;
}
@Deprecated
public static String trimEnding(String string, String endMatch) {
return trimEnd(string, endMatch);
}
/** @return a substring of given string without leading spaces. */
public static String trimLeadingSpaces(String string) {
int pos = 0;
while(pos < string.length() && string.charAt(pos) == ' ')
pos++;
return string.substring(pos);
}
/** @return a String of given length filled with spaces. */
public static String newSpaceFilledString(int length) {
return newFilledString(length, ' ');
}
/** @return a String of given length filled with given ch. */
public static String newFilledString(int length, char ch) {
char str[] = new char[length];
Arrays.fill(str, ch);
return new String(str);
}
/** @return a String of given length filled with given str. */
public static String newFilledString(int length, String str) {
StringBuffer sb = new StringBuffer(length * str.length());
for (int i = 0; i < length; i++ )
sb = sb.append(str);
return sb.toString();
}
/** Splits given string acording to given delimiter.
* @return an array with all the segments from the split string. */
public static String[] splitString(String string, char delimiter) {
final int count = occurrenceCount(string, delimiter);
String[] segments = new String[count + 1];
int startIx = 0;
for (int i = 0; i < count; i++) {
int endIx = string.indexOf(delimiter, startIx);
segments[i] = string.substring(startIx, endIx);
startIx = endIx + 1;
}
segments[count] = string.substring(startIx);
return segments;
}
/** Splits given string using given regex. Return the result as an {@link ArrayList}. */
public static ArrayList2<String> splitToList(String string, String regex) {
assertNotNull(string);
return ArrayList2.create(string.split(regex));
}
public static String prefixStr(String prefix, String string) {
return string == null ? "" : prefix + string;
}
public static String addSuffix(String string, String suffix) {
return mapSuffix(string, suffix, "");
}
public static String mapSuffix(String string, String suffix, String dflt) {
return emptyAsNull(string) == null ? dflt : string + suffix;
}
public static String joinUsingSep(String first, String sep, String second, boolean emptyAsNone) {
if(emptyAsNone) {
first = emptyAsNull(first);
second = emptyAsNull(second);
}
if(first != null && second != null) {
return first + sep + second;
}
return nullAsEmpty(first == null ? second : first);
}
public static String mapSurround(String prefix, String string, String suffix) {
return mapSurround(prefix, string, suffix, true, "");
}
public static String mapSurround(String prefix, String string, String suffix, boolean emptyAsNone) {
return mapSurround(prefix, string, suffix, emptyAsNone, "");
}
public static String mapSurround(String prefix, String string, String suffix, boolean emptyAsNone, String dflt) {
if(emptyAsNone) {
string = emptyAsNull(string);
}
if(string == null) {
return dflt;
}
return prefix + string + suffix;
}
public static String asString(String prefix, Object obj) {
return obj == null ? "" : prefix + obj.toString();
}
public static String commonPrefix(String... strings) {
assertTrue(strings.length > 0);
String firstString = strings[0];
int ix = 0;
boolean finished = false;
while(!finished) {
if(ix >= firstString.length()) {
break;
}
char ch = firstString.charAt(ix);
for(int othersIx = 1; othersIx < strings.length; othersIx++) {
String string = strings[othersIx];
if(ix >= string.length() || string.charAt(ix) != ch) {
finished = true;
break;
}
}
if(finished) {
break;
} else {
ix++;
}
}
return firstString.substring(0, ix);
}
}