/*
* The MIT License (MIT)
*
* Copyright (c) 2012 Lachlan Dowding
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package permafrost.tundra.lang;
import com.wm.data.IData;
import com.wm.data.IDataCursor;
import com.wm.data.IDataFactory;
import com.wm.data.IDataPortable;
import com.wm.data.IDataUtil;
import com.wm.util.Table;
import com.wm.util.coder.IDataCodable;
import com.wm.util.coder.ValuesCodable;
import permafrost.tundra.data.IDataHelper;
import permafrost.tundra.io.InputOutputHelper;
import permafrost.tundra.io.InputStreamHelper;
import permafrost.tundra.io.ReaderHelper;
import permafrost.tundra.math.BigDecimalHelper;
import permafrost.tundra.math.BigIntegerHelper;
import permafrost.tundra.math.DoubleHelper;
import permafrost.tundra.math.FloatHelper;
import permafrost.tundra.math.IntegerHelper;
import permafrost.tundra.math.LongHelper;
import permafrost.tundra.math.NumberHelper;
import permafrost.tundra.time.DateTimeHelper;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A collection of convenience methods for working with String objects.
*/
public final class StringHelper {
/**
* Disallow instantiation of this class.
*/
private StringHelper() {}
/**
* Normalizes the given byte[] as a string.
*
* @param bytes A byte[] to be converted to a string.
* @return A string representation of the given byte[].
*/
public static String normalize(byte[] bytes) {
return normalize(bytes, null);
}
/**
* Converts the given byte[] as a string.
*
* @param bytes A byte[] to be converted to a string.
* @param charset The character set to use.
* @return A string representation of the given byte[].
*/
public static String normalize(byte[] bytes, Charset charset) {
if (bytes == null) return null;
return new String(bytes, CharsetHelper.normalize(charset));
}
/**
* Converts the given java.io.InputStream as a String, and closes the stream.
*
* @param inputStream A java.io.InputStream to be converted to a string.
* @return A string representation of the given java.io.InputStream.
* @throws IOException If the given encoding is unsupported, or if there is an error reading from the
* java.io.InputStream.
*/
public static String normalize(InputStream inputStream) throws IOException {
return normalize(inputStream, CharsetHelper.DEFAULT_CHARSET);
}
/**
* Converts the given java.io.InputStream as a String, and closes the stream.
*
* @param inputStream A java.io.InputStream to be converted to a string.
* @param charset The character set to use.
* @return A string representation of the given java.io.InputStream.
* @throws IOException If there is an error reading from the java.io.InputStream.
*/
public static String normalize(InputStream inputStream, Charset charset) throws IOException {
if (inputStream == null) return null;
Writer writer = new StringWriter();
InputOutputHelper.copy(new InputStreamReader(InputStreamHelper.normalize(inputStream), CharsetHelper.normalize(charset)), writer);
return writer.toString();
}
/**
* Normalizes the given String, byte[], or java.io.InputStream object to a String.
*
* @param object The object to be normalized to a string.
* @return A string representation of the given object.
* @throws IOException If the given encoding is unsupported, or if there is an error reading from the
* java.io.InputStream.
*/
public static String normalize(Object object) throws IOException {
return normalize(object, null);
}
/**
* Normalizes the given String, byte[], or java.io.InputStream object to a String.
*
* @param object The object to be normalized to a string.
* @param charset The character set to use.
* @return A string representation of the given object.
* @throws IOException If there is an error reading from the java.io.InputStream.
*/
public static String normalize(Object object, Charset charset) throws IOException {
String value = null;
if (object instanceof String) {
value = (String)object;
} else if (object instanceof Boolean) {
value = BooleanHelper.emit((Boolean)object);
} else if (object instanceof Number) {
value = NumberHelper.emit((Number)object);
} else if (object instanceof InputStream) {
value = normalize((InputStream)object, charset);
} else if (object instanceof byte[]) {
value = normalize((byte[])object, charset);
} else if (object instanceof Reader) {
value = ReaderHelper.read((Reader)object);
} else if (object instanceof Class) {
value = ((Class)object).getName();
} else if (object != null) {
value = object.toString();
}
return value;
}
/**
* Normalizes the list of String, byte[], or InputStream to a String list.
*
* @param array The array of objects to be normalized.
* @param charset The character set to use.
* @return The resulting String list representing the given array.
* @throws IOException If there is an error reading from the java.io.InputStream.
*/
public static String[] normalize(Object[] array, Charset charset) throws IOException {
if (array == null) return null;
String[] output = new String[array.length];
for (int i = 0; i < array.length; i++) {
output[i] = normalize(array[i], charset);
}
return output;
}
/**
* Normalizes the list of String, byte[], or InputStream to a String list.
*
* @param array The array of objects to be normalized.
* @param charsetName The character set to use.
* @return The resulting String list representing the given array.
* @throws IOException If there is an error reading from the java.io.InputStream.
*/
public static String[] normalize(Object[] array, String charsetName) throws IOException {
return normalize(array, CharsetHelper.normalize(charsetName));
}
/**
* Returns a substring starting at the given index for the given length.
*
* @param input The string to be sliced.
* @param index The zero-based starting index of the slice.
* @param length The length in characters of the slice.
* @return The resulting substring.
*/
public static String slice(String input, int index, int length) {
if (input == null || input.equals("")) return input;
String output = "";
int inputLength = input.length(), endIndex = 0;
// support reverse length
if (length < 0) {
// support reverse indexing
if (index < 0) {
endIndex = index + inputLength + 1;
} else {
if (index >= inputLength) index = inputLength - 1;
endIndex = index + 1;
}
index = endIndex + length;
} else {
// support reverse indexing
if (index < 0) index += inputLength;
endIndex = index + length;
}
if (index < inputLength && endIndex > 0) {
if (index < 0) index = 0;
if (endIndex > inputLength) endIndex = inputLength;
output = input.substring(index, endIndex);
}
return output;
}
/**
* Truncates the given string to the given length. If the string length is less than or equal to the desired
* length it is returned unmodified, otherwise it is truncated to the desired length.
*
* @param input The string to be truncated.
* @param length The length to truncate the string to.
* @return The truncated string.
*/
public static String truncate(String input, int length) {
return truncate(input, length, false);
}
/**
* Truncates the given string to the given length. If the string length is less than or equal to the desired
* length it is returned unmodified, otherwise it is truncated to the desired length.
*
* @param input The string to be truncated.
* @param length The length to truncate the string to.
* @param ellipsis If true, the returned string is suffixed with an ellipsis character when truncated.
* @return The truncated string.
*/
public static String truncate(String input, int length, boolean ellipsis) {
if (input == null) return null;
if (input.length() > Math.abs(length)) {
if (ellipsis && length != 0) {
if (length > 0) {
input = slice(input, 0, length - 1) + "…";
} else {
input = "…" + slice(input, -1, length + 1);
}
} else if (length < 0){
input = slice(input, -1, length);
} else {
input = slice(input, 0, length);
}
}
return input;
}
/**
* Truncates the given strings to the given length. If a string's length is less than or equal to the desired
* length it is returned unmodified, otherwise it is truncated to the desired length.
*
* @param input The strings to be truncated.
* @param length The length to truncate the strings to.
* @param ellipsis If true, the returned strings are suffixed with an ellipsis character when truncated.
* @return The truncated strings.
*/
public static String[] truncate(String[] input, int length, boolean ellipsis) {
if (input == null) return null;
String output[] = new String[input.length];
for(int i = 0; i < input.length; i++) {
output[i] = truncate(input[i], length, ellipsis);
}
return output;
}
/**
* Truncates the given strings to the given length. If a string's length is less than or equal to the desired
* length it is returned unmodified, otherwise it is truncated to the desired length.
*
* @param input The strings to be truncated.
* @param length The length to truncate the strings to.
* @param ellipsis If true, the returned strings are suffixed with an ellipsis character when truncated.
* @return The truncated strings.
*/
public static String[][] truncate(String[][] input, int length, boolean ellipsis) {
if (input == null) return null;
String output[][] = new String[input.length][];
for(int i = 0; i < input.length; i++) {
output[i] = truncate(input[i], length, ellipsis);
}
return output;
}
/**
* Recursively truncates all strings in the given IData document to the given length. If a string's length is less
* than or equal to the desired length it is returned unmodified, otherwise it is truncated to the desired length.
*
* @param input The IData document containing strings to be truncated.
* @param length The length to truncate the strings to.
* @param ellipsis If true, the returned strings are suffixed with an ellipsis character when truncated.
* @return A new IData document containing the truncated strings.
*/
public static IData truncate(IData input, int length, boolean ellipsis) {
if (input == null) return null;
IData output = IDataFactory.create();
IDataCursor inputCursor = input.getCursor();
IDataCursor outputCursor = output.getCursor();
try {
while(inputCursor.next()) {
String key = inputCursor.getKey();
Object value = inputCursor.getValue();
if (value instanceof IData[] || value instanceof Table || value instanceof IDataCodable[] || value instanceof IDataPortable[] || value instanceof ValuesCodable[]) {
value = truncate(IDataHelper.toIDataArray(value), length, ellipsis);
} else if (value instanceof IData || value instanceof IDataCodable || value instanceof IDataPortable || value instanceof ValuesCodable) {
value = truncate(IDataHelper.toIData(value), length, ellipsis);
} else if (value instanceof String) {
value = truncate((String)value, length, ellipsis);
} else if (value instanceof String[]) {
value = truncate((String[])value, length, ellipsis);
} else if (value instanceof String[][]) {
value = truncate((String[][])value, length, ellipsis);
}
outputCursor.insertAfter(key, value);
}
} finally {
inputCursor.destroy();
outputCursor.destroy();
}
return output;
}
/**
* Recursively truncates all strings in the given IData[] document list to the given length. If a string's length
* is less than or equal to the desired length it is returned unmodified, otherwise it is truncated to the desired
* length.
*
* @param input The IData[] document list containing strings to be truncated.
* @param length The length to truncate the strings to.
* @param ellipsis If true, the returned strings are suffixed with an ellipsis character when truncated.
* @return A new IData[] document list containing the truncated strings.
*/
public static IData[] truncate(IData[] input, int length, boolean ellipsis) {
if (input == null) return null;
IData[] output = new IData[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = truncate(input[i], length, ellipsis);
}
return output;
}
/**
* Converts a null input string to an empty string, or returns the string unmodified if not null.
*
* @param input The string to be converted to an empty string if null.
* @return If input is null then empty string, otherwise input string unmodified.
*/
public static String blankify(String input) {
return blankify(input, true);
}
/**
* Converts a null input string to an empty string, or returns the string unmodified if not null.
*
* @param input The string to be converted to an empty string if null.
* @param blankify If true, nulls will be converted to empty strings, else no conversion will occur.
* @return If blankify is true and input is null then empty string, otherwise input string unmodified.
*/
public static String blankify(String input, boolean blankify) {
if (!blankify) return input;
return input == null ? "" : input;
}
/**
* Converts any null strings to empty strings, or returns the strings unmodified if not null.
*
* @param input The list of strings to be converted to an empty strings if null.
* @return The list of strings converted to empty strings if they were null.
*/
public static String[] blankify(String[] input) {
return blankify(input, true);
}
/**
* Converts any null strings to empty strings, or returns the strings unmodified if not null.
*
* @param input The list of strings to be converted to an empty strings if null.
* @param blankify If true, nulls will be converted to empty strings, else no conversion will occur.
* @return The list of strings converted to empty strings if they were null.
*/
public static String[] blankify(String input[], boolean blankify) {
if (!blankify || input == null) return input;
String output[] = new String[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = blankify(input[i], blankify);
}
return output;
}
/**
* Capitalizes the first character in either the first word or all words in the given string.
*
* @param string The string to capitalize.
* @param firstWordOnly Whether only the first word should be capitalized, or all words.
* @return The capitalized string.
*/
public static String capitalize(String string, boolean firstWordOnly) {
if (string == null) return null;
char[] characters = string.toCharArray();
boolean capitalize = true;
for (int i = 0; i < characters.length; i++) {
char character = characters[i];
if (Character.isWhitespace(character)) {
capitalize = true;
} else if (capitalize) {
characters[i] = Character.toTitleCase(character);
capitalize = false;
if (firstWordOnly) break;
}
}
return new String(characters);
}
/**
* Capitalizes the first character in either the first word or all words in each of the given
* strings.
*
* @param input The strings to capitalize.
* @param firstWordOnly Whether only the first word should be capitalized, or all words.
* @return The capitalized strings.
*/
public static String[] capitalize(String[] input, boolean firstWordOnly) {
if (input == null) return null;
String[] output = new String[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = capitalize(input[i], firstWordOnly);
}
return output;
}
/**
* Returns the given string as a list of characters.
*
* @param string The string.
* @return The characters in the given string.
*/
public static Character[] characters(String string) {
if (string == null) return null;
char[] chars = string.toCharArray();
Character[] characters = new Character[chars.length];
for (int i = 0; i < chars.length; i++) {
characters[i] = chars[i];
}
return characters;
}
/**
* Concatenates all non-null string leaf values in the given IData document.
*
* @param operands An IData document containing strings to be concatenated.
* @return All string leaf values in the IData document concatenated together.
*/
public static String concatenate(IData operands) {
return concatenate(operands, null, false);
}
/**
* Concatenates all non-null string leaf values in the given IData document, separated by the given separator
* string.
*
* @param operands An IData document containing strings to be concatenated.
* @param separator An optional separator string to be used between items of the array.
* @return All string leaf values in the IData document concatenated together.
*/
public static String concatenate(IData operands, String separator) {
return concatenate(operands, separator, false);
}
/**
* Concatenates all string leaf values in the given IData document, separated by the given separator string.
*
* @param operands An IData document containing strings to be concatenated.
* @param separator An optional separator string to be used between items of the array.
* @param includeNulls If true, null values will be included in the output string, otherwise they are ignored.
* @return All string leaf values in the IData document concatenated together.
*/
@SuppressWarnings("unchecked")
public static String concatenate(IData operands, String separator, boolean includeNulls) {
return concatenate(separator, includeNulls, (String[])IDataHelper.getLeafValues(operands, String.class));
}
/**
* Concatenates all given non-null strings.
*
* @param strings A list of strings to be concatenated.
* @return All given strings concatenated together.
*/
public static String concatenate(String ...strings) {
return concatenate(null, false, strings);
}
/**
* Concatenates all given strings, separated by the given separator string.
*
* @param separator An optional separator string to be used between items of the array.
* @param strings A list of strings to be concatenated.
* @return All given strings concatenated together.
*/
public static String concatenate(String separator, String ...strings) {
return concatenate(separator, false, strings);
}
/**
* Concatenates all given strings, separated by the given separator string.
*
* @param separator An optional separator string to be used between items of the array.
* @param includeNulls If true, null values will be included in the output string, otherwise they are ignored.
* @param strings A list of strings to be concatenated.
* @return All given strings concatenated together.
*/
public static String concatenate(String separator, boolean includeNulls, String ...strings) {
if (strings == null || strings.length == 0) return includeNulls ? null : "";
StringBuilder builder = new StringBuilder();
boolean separatorRequired = false;
for (String string : strings) {
boolean includeItem = includeNulls || string != null;
if (separator != null && separatorRequired && includeItem) builder.append(separator);
if (includeItem) {
builder.append(string);
separatorRequired = true;
}
}
return builder.toString();
}
/**
* Returns the given string with leading and trailing whitespace removed.
*
* @param string The string to be trimmed.
* @return The trimmed string.
*/
public static String trim(String string) {
String output = null;
if (string != null) output = string.trim();
return output;
}
/**
* Trims each item in the given String[] of leading and trailing whitespace.
*
* @param input The String[] to be trimmed.
* @return A new String[] contained the trimmed versions of the items in the given input.
*/
public static String[] trim(String[] input) {
if (input == null) return null;
String[] output = new String[input.length];
for (int i = 0; i < input.length; i++) {
String item = input[i];
if (item != null) output[i] = input[i].trim();
}
return output;
}
/**
* Trims each item in the given String[][] of leading and trailing whitespace.
*
* @param input The String[][] to be trimmed.
* @return A new String[][] contained the trimmed versions of the items in the given input.
*/
public static String[][] trim(String[][] input) {
if (input == null) return null;
String[][] output = new String[input.length][];
for (int i = 0; i < input.length; i++) {
output[i] = trim(input[i]);
}
return output;
}
/**
* Returns the length or number of characters of the string.
*
* @param string The string to be measured.
* @return The length of the given string.
*/
public static int length(String string) {
int length = 0;
if (string != null) length = string.length();
return length;
}
/**
* Returns all the groups captured by the given regular expression pattern in the given string.
*
* @param string The string to match against the regular expression.
* @param pattern The regular expression pattern.
* @return The capture groups from the regular expression pattern match against the string.
*/
public static IData[] capture(String string, String pattern) {
if (string == null || pattern == null) return null;
List<IData> captures = new ArrayList<IData>();
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(string);
while (matcher.find()) {
int count = matcher.groupCount();
List<IData> groups = new ArrayList<IData>(count);
for (int i = 0; i <= count; i++) {
int index = matcher.start(i);
int length = matcher.end(i) - index;
String content = matcher.group(i);
boolean captured = index >= 0;
IData group = IDataFactory.create();
IDataCursor groupCursor = group.getCursor();
IDataUtil.put(groupCursor, "captured?", "" + captured);
if (captured) {
IDataUtil.put(groupCursor, "index", "" + index);
IDataUtil.put(groupCursor, "length", "" + length);
IDataUtil.put(groupCursor, "content", content);
}
groupCursor.destroy();
groups.add(group);
}
IData capture = IDataFactory.create();
IDataCursor captureCursor = capture.getCursor();
IDataUtil.put(captureCursor, "groups", groups.toArray(new IData[groups.size()]));
IDataUtil.put(captureCursor, "groups.length", "" + groups.size());
captureCursor.destroy();
captures.add(capture);
}
return captures.toArray(new IData[captures.size()]);
}
/**
* Returns true if the given regular expression pattern is found anywhere in the given string.
*
* @param string The string to match against the regular expression.
* @param pattern The regular expression pattern.
* @return True if the regular expression pattern was found anywhere in the given string.
*/
public static boolean find(String string, String pattern) {
return find(string, pattern, false);
}
/**
* /** Returns true if the given pattern is found anywhere in the given string.
*
* @param string The string to match against the regular expression.
* @param pattern The literal of regular expression pattern.
* @param literal Whether the pattern is a literal pattern or a regular expression.
* @return True if the pattern was found anywhere in the given string.
*/
public static boolean find(String string, String pattern, boolean literal) {
boolean found = false;
if (string != null && pattern != null) {
if (literal) {
found = string.contains(pattern);
} else {
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(string);
found = matcher.find();
}
}
return found;
}
/**
* Returns true if the given regular expression pattern matches the entirety of the given string.
*
* @param string The string to match against the regular expression.
* @param pattern The regular expression pattern.
* @return True if the regular expression matches the entirety of the given string.
*/
public static boolean match(String string, String pattern) {
return match(string, pattern, false);
}
/**
* Returns true if the pattern matches the entirety of the given string.
*
* @param string The string to match against the regular expression.
* @param pattern The literal or regular expression pattern.
* @param literal Whether the pattern is a literal pattern or a regular expression.
* @return True if the pattern matches the entirety of the given string.
*/
public static boolean match(String string, String pattern, boolean literal) {
boolean match = false;
if (string != null && pattern != null) {
if (literal) {
match = string.equals(pattern);
} else {
match = string.matches(pattern);
}
}
return match;
}
/**
* Removes all occurrences of the given regular expression in the given string.
*
* @param string The string to remove the pattern from.
* @param pattern The regular expression pattern to be removed.
* @return The given string with all occurrences of the given pattern removed.
*/
public static String remove(String string, String pattern) {
return remove(string, pattern, false);
}
/**
* Removes either the first or all occurrences of the given regular expression in the given string.
*
* @param string The string to remove the pattern from.
* @param pattern The regular expression pattern to be removed.
* @param firstOnly If true, only the first occurrence is removed, otherwise all occurrences are removed.
* @return The given string with either the first or all occurrences of the given pattern removed.
*/
public static String remove(String string, String pattern, boolean firstOnly) {
return replace(string, pattern, "", true, firstOnly);
}
/**
* Replaces all occurrences of the given regular expression in the given string with the given replacement.
*
* @param string The string to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param literal Whether the replacement string is literal and therefore requires quoting.
* @return The replaced string.
*/
public static String replace(String string, String pattern, String replacement, boolean literal) {
return replace(string, pattern, replacement, literal, false);
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string with the given
* replacement.
*
* @param string The string to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param literal Whether the replacement string is literal and therefore requires quoting.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The replaced string.
*/
public static String replace(String string, String pattern, String replacement, boolean literal, boolean firstOnly) {
return replace(string, pattern == null ? null : Pattern.compile(pattern), replacement != null && literal ? Matcher.quoteReplacement(replacement) : replacement, firstOnly);
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string with the given
* replacement.
*
* @param string The string to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The replaced string.
*/
public static String replace(String string, Pattern pattern, String replacement, boolean firstOnly) {
if (string == null || pattern == null || replacement == null) return string;
Matcher matcher = pattern.matcher(string);
if (firstOnly) {
string = matcher.replaceFirst(replacement);
} else {
string = matcher.replaceAll(replacement);
}
return string;
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string array elements
* with the given replacement.
*
* @param array The string array whose elements are to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The string array with replaced string elements.
*/
public static String[] replace(String[] array, String pattern, String replacement, boolean literal, boolean firstOnly) {
return replace(array, pattern == null ? null : Pattern.compile(pattern), replacement != null && literal ? Matcher.quoteReplacement(replacement) : null, firstOnly);
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string array elements
* with the given replacement.
*
* @param array The string array whose elements are to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The string array with replaced string elements.
*/
public static String[] replace(String[] array, Pattern pattern, String replacement, boolean firstOnly) {
if (array == null || pattern == null || replacement == null) return array;
String[] output = new String[array.length];
for (int i = 0; i < array.length; i++) {
output[i] = replace(array[i], pattern, replacement, firstOnly);
}
return output;
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string table elements
* with the given replacement.
*
* @param table The string table whose elements are to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The string table with replaced string elements
*/
public static String[][] replace(String[][] table, String pattern, String replacement, boolean literal, boolean firstOnly) {
return replace(table, pattern == null ? null : Pattern.compile(pattern), replacement != null && literal ? Matcher.quoteReplacement(replacement) : null, firstOnly);
}
/**
* Replaces either the first or all occurrences of the given regular expression in the given string table elements
* with the given replacement.
*
* @param table The string table whose elements are to be replaced.
* @param pattern The regular expression pattern.
* @param replacement The replacement string.
* @param firstOnly If true, only the first occurrence is replaced, otherwise all occurrences are replaced.
* @return The string table with replaced string elements.
*/
public static String[][] replace(String[][] table, Pattern pattern, String replacement, boolean firstOnly) {
if (table == null || pattern == null || replacement == null) return table;
String[][] output = new String[table.length][];
for (int i = 0; i < table.length; i++) {
output[i] = replace(table[i], pattern, replacement, firstOnly);
}
return output;
}
/**
* Splits a string around each match of the given regular expression pattern.
*
* @param string The string to be split.
* @param pattern The regular expression pattern to split around.
* @return The array of strings computed by splitting the given string around matches of this pattern.
*/
public static String[] split(String string, String pattern) {
return split(string, pattern, false);
}
/**
* Splits a string around each match of the given pattern.
*
* @param string The string to be split.
* @param pattern The literal or regular expression pattern to split around.
* @param literal Whether the pattern is a literal pattern or a regular expression.
* @return The array of strings computed by splitting the given string around matches of this pattern.
*/
public static String[] split(String string, String pattern, boolean literal) {
String[] output = null;
if (string != null && pattern != null) {
if (literal) pattern = quote(pattern);
output = Pattern.compile(pattern).split(string);
} else if (string != null) {
output = new String[1];
output[0] = string;
}
return output;
}
/**
* Returns all the lines in the given string as an array.
*
* @param string The string to be split into lines.
* @return The array of lines from the given string.
*/
public static String[] lines(String string) {
return split(string, "\n");
}
/**
* Trims the given string of leading and trailing whitespace, and optionally replaces runs of whitespace characters
* with a single space character.
*
* @param string The string to be squeezed.
* @param internal Whether runs of whitespace characters should be replaced with a single space character.
* @return The squeezed string.
*/
public static String squeeze(String string, boolean internal) {
if (string == null) return null;
string = string.trim();
if (internal) string = replace(string, "\\s+", " ", true);
return string.equals("") ? null : string;
}
/**
* Trims the given string of leading and trailing whitespace, and replaces runs of whitespace characters with a
* single space character.
*
* @param string The string to be squeezed.
* @return The squeezed string.
*/
public static String squeeze(String string) {
return squeeze(string, true);
}
/**
* Returns a literal regular expression pattern for the given string.
*
* @param string The string to quote.
* @return A regular expression pattern which literally matches the given string.
*/
public static String quote(String string) {
if (string == null) return null;
return Pattern.quote(string);
}
/**
* Returns a regular expression pattern that matches any of the values in the given string list.
*
* @param array The list of strings to be matched.
* @return A regular expression which literally matches any of the given strings.
*/
public static String quote(String[] array) {
if (array == null) return null;
int last = array.length - 1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < array.length; i++) {
if (i == 0) builder.append("(");
builder.append(quote(array[i]));
if (i < last) builder.append("|");
if (i == last) builder.append(")");
}
return builder.toString();
}
/**
* Pads a string with the given character to the given length.
*
* @param string The string to pad.
* @param length The desired length of the string. If less than 0 the string is padded right to left, otherwise
* it is padded from left to right.
* @param character The character to pad the string with.
* @return The padded string.
*/
public static String pad(String string, int length, char character) {
if (string == null) string = "";
boolean left = length >= 0;
if (length < 0) length = length * -1;
if (string.length() >= length) return string;
StringBuilder builder = new StringBuilder(length);
if (!left) builder.append(string);
for (int i = string.length(); i < length; i++) {
builder.append(character);
}
if (left) builder.append(string);
return builder.toString();
}
/**
* Pads each string in the given list with the given character to the given length.
*
* @param input The list of strings to be padded.
* @param length The desired length of the strings. If less than 0 the strings are padded right to left, otherwise
* they are padded from left to right.
* @param character The character to pad the strings with.
* @return The list of padded strings.
*/
public static String[] pad(String[] input, int length, char character) {
if (input == null) return null;
String[] output = new String[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = pad(input[i], length, character);
}
return output;
}
/**
* Compares two strings lexicographically.
*
* @param string1 The first string to compare.
* @param string2 The second string to compare.
* @return Less than 0 if the first string is less than the second string, equal to 0 if the two strings are equal,
* or greater than 0 if the first string is greater than the second string.
*/
public static int compare(String string1, String string2) {
return compare(string1, string2, false, false);
}
/**
* Compares two strings lexicographically.
*
* @param string1 The first string to compare.
* @param string2 The second string to compare.
* @param caseInsensitive Whether the comparison should be case insensitive.
* @return Less than 0 if the first string is less than the second string, equal to 0 if the two strings are equal,
* or greater than 0 if the first string is greater than the second string.
*/
public static int compare(String string1, String string2, boolean caseInsensitive) {
return compare(string1, string2, caseInsensitive, false);
}
/**
* Compares two strings lexicographically.
*
* @param string1 The first string to compare.
* @param string2 The second string to compare.
* @param caseInsensitive Whether the comparison should be case insensitive.
* @param whitespaceInsensitive Whether the comparison should be whitespace insensitive.
* @return Less than 0 if the first string is less than the second string, equal to 0 if the two strings are equal,
* or greater than 0 if the first string is greater than the second string.
*/
public static int compare(String string1, String string2, boolean caseInsensitive, boolean whitespaceInsensitive) {
if (string1 == null && string2 == null) return 0;
if (string1 == null) return -1;
if (string2 == null) return 1;
if (whitespaceInsensitive) {
string1 = string1.replaceAll("\\s", "");
string2 = string2.replaceAll("\\s", "");
}
if (caseInsensitive) {
return string1.compareToIgnoreCase(string2);
} else {
return string1.compareTo(string2);
}
}
/**
* Returns a formatted string using the specified pattern and arguments.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param scope An IData document which contains the argument values referenced by the given argument keys.
* @param arguments The list of arguments to be fetched from the record and normalized to the specified types.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, IData scope) {
return format(locale, pattern, arguments, null, scope);
}
/**
* Returns a formatted string using the specified pattern and arguments.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param scope An IData document which contains the argument values referenced by the given argument keys.
* @param arguments The list of arguments to be fetched from the record and normalized to the specified types.
* @param index The zero-based array index for this record if it is part of a list that is being formatted.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, IData scope, int index) {
return format(locale, pattern, arguments, null, scope, 0);
}
/**
* Returns a formatted string using the specified pattern and arguments.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param pipeline The pipeline against which absolute argument keys are resolved.
* @param scope An IData document which contains the argument values referenced by the given argument keys.
* @param arguments The list of arguments to be fetched from the record and normalized to the specified types.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, IData pipeline, IData scope) {
return format(locale, pattern, arguments, pipeline, scope, 0);
}
/**
* Returns a formatted string using the specified pattern and arguments.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param pipeline The pipeline against which absolute argument keys are resolved.
* @param scope An IData document which contains the argument values referenced by the given argument keys.
* @param arguments The list of arguments to be fetched from the record and normalized to the specified types.
* @param index The zero-based array index for this record if it is part of a list that is being formatted.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, IData pipeline, IData scope, int index) {
if (pattern == null || arguments == null || scope == null) return null;
List<Object> args = new ArrayList<Object>(arguments == null? 0 : arguments.length);
for (IData argument : arguments) {
if (argument != null) {
IDataCursor cursor = argument.getCursor();
String key = IDataUtil.getString(cursor, "key");
Object value = IDataUtil.get(cursor, "value");
String type = IDataUtil.getString(cursor, "type");
String argPattern = IDataUtil.getString(cursor, "pattern");
boolean blankify = BooleanHelper.parse(IDataUtil.getString(cursor, "blankify?"));
cursor.destroy();
if (key != null && value == null) {
value = IDataHelper.get(pipeline, scope, key);
if (value == null) {
if (key.equals("$index")) {
value = index;
} else if (key.equals("$iteration")) {
value = index + 1;
}
}
}
if (value != null) {
if (type == null || type.equalsIgnoreCase("string")) {
value = value.toString();
} else if (type.equalsIgnoreCase("integer")) {
value = BigIntegerHelper.normalize(value);
} else if (type.equalsIgnoreCase("decimal")) {
value = BigDecimalHelper.normalize(value);
} else if (type.equalsIgnoreCase("datetime")) {
value = DateTimeHelper.normalize(value, argPattern);
}
} else if (blankify) {
if (type == null || type.equalsIgnoreCase("string")) {
value = "";
} else if (type.equalsIgnoreCase("integer")) {
value = BigInteger.ZERO;
} else if (type.equalsIgnoreCase("decimal")) {
value = BigDecimal.ZERO;
}
}
args.add(value);
}
}
return String.format(locale, pattern, args.toArray(new Object[args.size()]));
}
/**
* Returns a formatted string produced by formatting each given record using the specified pattern and
* arguments, separated by the given separator string.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param arguments The list of arguments to be fetched from each record and normalized to the specified types.
* @param recordSeparator An optional string for separating each formatted record in the resulting string.
* @param records An IData[] document list where each item contains a set of argument values.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, String recordSeparator, IData ... records) {
return format(locale, pattern, arguments, null, recordSeparator, records);
}
/**
* Returns a formatted string produced by formatting each given record using the specified pattern and
* arguments, separated by the given separator string.
*
* @param locale The locale to apply during formatting. If null then no localization is applied.
* @param pattern A format string, as per http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html.
* @param arguments The list of arguments to be fetched from each record and normalized to the specified types.
* @param pipeline The pipeline against which absolute argument keys are resolved.
* @param recordSeparator An optional string for separating each formatted record in the resulting string.
* @param records An IData[] document list where each item contains a set of argument values.
* @return A formatted string.
*/
public static String format(Locale locale, String pattern, IData[] arguments, IData pipeline, String recordSeparator, IData ... records) {
if (pattern == null || arguments == null || records == null) return null;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < records.length; i++) {
builder.append(format(locale, pattern, arguments, pipeline, records[i], i));
if (recordSeparator != null) builder.append(recordSeparator);
}
return builder.toString();
}
/**
* Returns null if the given string only contains whitespace characters.
*
* @param input The string to be nullified.
* @return Null if the given string only contains whitespace characters, otherwise the given string unmodified.
*/
public static String nullify(String input) {
return nullify(input, true);
}
/**
* Returns null if the given string only contains whitespace characters.
*
* @param input The string to be nullified.
* @param nullify If true, the string will be nullified.
* @return Null if the given string only contains whitespace characters, otherwise the given string unmodified.
*/
public static String nullify(String input, boolean nullify) {
return (nullify && (input == null || input.trim().equals(""))) ? null : input;
}
/**
* Converts each string in the given list to null if it only contains whitespace characters.
*
* @param input The string list to be nullified.
* @return The nullified list of strings.
*/
public static String[] nullify(String[] input) {
return nullify(input, true);
}
/**
* Converts each string in the given list to null if it only contains whitespace characters.
*
* @param input The string list to be nullified.
* @param nullify If true, the list will be nullified.
* @return The nullified list of strings.
*/
public static String[] nullify(String[] input, boolean nullify) {
if (!nullify || input == null) return null;
String[] output = new String[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = nullify(input[i], nullify);
}
return output;
}
/**
* Repeats the given string atom the given count times, returning the result.
*
* @param atom A string to be repeated.
* @param count The number of times to repeat the string.
* @return A new string containing the given string atom repeated the given number of times.
*/
public static String repeat(String atom, int count) {
if (atom == null) return null;
if (count < 0) throw new IllegalArgumentException("count must be >= 0");
// short-circuit when only 1 repeat is required
if (count == 1) return atom;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < count; i++) {
builder.append(atom);
}
return builder.toString();
}
/**
* Reverses the given string.
*
* @param input A string to be reversed.
* @return The reverse of the given string.
*/
public static String reverse(String input) {
return input == null ? null : new StringBuilder(input).reverse().toString();
}
}