Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
liquibase.util.StringUtil Maven / Gradle / Ivy
Go to download
Liquibase is a tool for managing and executing database changes.
package liquibase.util;
import liquibase.ExtensibleObject;
import liquibase.GlobalConfiguration;
import liquibase.Scope;
import liquibase.changelog.ChangeSet;
import liquibase.parser.LiquibaseSqlParser;
import liquibase.parser.SqlParserFactory;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringUtil {
private static final Pattern upperCasePattern = Pattern.compile(".*[A-Z].*");
private static final Pattern lowerCasePattern = Pattern.compile(".*[a-z].*");
private static final Pattern spacePattern = Pattern.compile(" ");
/**
* Returns the trimmed (left and right) version of the input string. If null is passed, an empty string is returned.
*
* @param string the input string to trim
* @return the trimmed string, or an empty string if the input was null.
* @deprecated use {@link StringUtils#trimToEmpty(String)} instead
*/
@Deprecated
public static String trimToEmpty(String string) {
return StringUtils.trimToEmpty(string);
}
/**
* Returns the trimmed (left and right) form of the input string. If the string is empty after trimming (or null
* was passed in the first place), null is returned, i.e. the input string is reduced to nothing.
*
* @param string the string to trim
* @return the trimmed string or null
* @deprecated use {@link StringUtils#trimToNull(String)} instead
*/
@Deprecated
public static String trimToNull(String string) {
return StringUtils.trimToNull(string);
}
/**
* Removes any comments from multiple line SQL using {@link #stripComments(String, ChangeSet)}
* and then extracts each individual statement using {@link #splitSQL(String, String, ChangeSet)}.
*
* @param multiLineSQL A String containing all the SQL statements
* @param stripComments If true then comments will be stripped, if false then they will be left in the code
*/
public static String[] processMultiLineSQL(String multiLineSQL, boolean stripComments, boolean splitStatements, String endDelimiter) {
return processMultiLineSQL(multiLineSQL, stripComments, splitStatements, endDelimiter, null);
}
/**
* Removes any comments from multiple line SQL using {@link #stripComments(String, ChangeSet)}
* and then extracts each individual statement using {@link #splitSQL(String, String, ChangeSet)}.
*
* @param multiLineSQL A String containing all the SQL statements
* @param stripComments If true then comments will be stripped, if false then they will be left in the code
* @param changeSet the changeset associated with the sql being parsed
*/
public static String[] processMultiLineSQL(String multiLineSQL, boolean stripComments, boolean splitStatements, String endDelimiter, ChangeSet changeSet) {
SqlParserFactory sqlParserFactory = Scope.getCurrentScope().getSingleton(SqlParserFactory.class);
LiquibaseSqlParser sqlParser = sqlParserFactory.getSqlParser();
StringClauses parsed = sqlParser.parse(multiLineSQL, true, !stripComments, changeSet);
List returnArray = new ArrayList<>();
StringBuilder currentString = new StringBuilder();
String previousPiece = null;
boolean previousDelimiter = false;
List parsedArray = Arrays.asList(parsed.toArray(true));
int isInClause = 0;
List tokens = mergeTokens(parsedArray, endDelimiter);
for (int i = 0; i < tokens.size(); i++) {
Object piece = tokens.get(i);
String nextPiece = null;
int nextIndex = i + 1;
while (nextPiece == null && nextIndex < tokens.size()) {
nextPiece = StringUtil.trimToNull(String.valueOf(tokens.get(nextIndex)));
nextIndex++;
}
if (piece instanceof String && ((String) piece).equalsIgnoreCase("BEGIN")
&& (!"transaction".equalsIgnoreCase(nextPiece)
&& !"trans".equalsIgnoreCase(nextPiece)
&& !"tran".equalsIgnoreCase(nextPiece))
&& !"dialog".equalsIgnoreCase(nextPiece)
&& !"conversation".equalsIgnoreCase(nextPiece)
&& !"distributed".equalsIgnoreCase(nextPiece)) {
isInClause++;
}
if (piece instanceof String && ((String) piece).equalsIgnoreCase("END") && isInClause > 0
&& (!"transaction".equalsIgnoreCase(nextPiece)
&& !"trans".equalsIgnoreCase(nextPiece)
&& !"tran".equalsIgnoreCase(nextPiece))) {
isInClause--;
}
if (isInClause == 0 && splitStatements && (piece instanceof String) && isDelimiter((String) piece, previousPiece, endDelimiter)) {
String trimmedString;
if (Boolean.TRUE.equals(GlobalConfiguration.STRICT.getCurrentValue())) {
String sentenceWithoutDelimiter = removeEndDelimiterIfItsASlash(endDelimiter, currentString);
trimmedString = sentenceWithoutDelimiter.isEmpty() ? StringUtils.trimToNull(currentString.toString()) : StringUtils.trimToNull(sentenceWithoutDelimiter);
} else {
trimmedString = StringUtils.trimToNull(currentString.toString());
}
if (trimmedString != null) {
returnArray.add(trimmedString);
}
currentString = new StringBuilder();
previousDelimiter = true;
} else {
if (!previousDelimiter || (StringUtils.trimToNull((String) piece) != null)) { //don't include whitespace after a delimiter
if ((currentString.length() > 0) || (StringUtils.trimToNull((String) piece) != null)) { //don't include whitespace before the statement
currentString.append(piece);
}
}
previousDelimiter = false;
}
previousPiece = (String) piece;
}
String trimmedString = StringUtils.trimToNull(currentString.toString());
if (trimmedString != null) {
returnArray.add(trimmedString);
}
return returnArray.toArray(new String[0]);
}
private static String removeEndDelimiterIfItsASlash(String endDelimiter, StringBuilder currentString) {
String sentenceWithoutDelimiter = "";
if(endDelimiter != null && "/".contentEquals(endDelimiter)) {
int lastIndexEndDelimiter = currentString.toString().lastIndexOf(endDelimiter);
if(lastIndexEndDelimiter >= 0) {
sentenceWithoutDelimiter = currentString.substring(0, lastIndexEndDelimiter);
}
}
return sentenceWithoutDelimiter;
}
/**
* Removes any comments from multiple line SQL using {@link #stripComments(String, ChangeSet)}
* and then extracts each individual statement using {@link #splitSQL(String, String, ChangeSet)}.
*
* @param multiLineSQL A String containing all the SQL statements
* @param stripComments If true then comments will be stripped, if false then they will be left in the code
* @deprecated The new method is {@link #processMultiLineSQL(String, boolean, boolean, String, ChangeSet)} (String)}
*/
@Deprecated
public static String[] processMutliLineSQL(String multiLineSQL, boolean stripComments, boolean splitStatements, String endDelimiter) {
return processMultiLineSQL(multiLineSQL, stripComments, splitStatements, endDelimiter, null);
}
/**
* Removes any comments from multiple line SQL using {@link #stripComments(String, ChangeSet)}
* and then extracts each individual statement using {@link #splitSQL(String, String, ChangeSet)}.
*
* @param multiLineSQL A String containing all the SQL statements
* @param stripComments If true then comments will be stripped, if false then they will be left in the code
* @param changeSet the changeset associated with the sql being parsed
* @deprecated The new method is {@link #processMultiLineSQL(String, boolean, boolean, String, ChangeSet)} (String)}
*/
@Deprecated
public static String[] processMutliLineSQL(String multiLineSQL, boolean stripComments, boolean splitStatements, String endDelimiter, ChangeSet changeSet) {
return processMultiLineSQL(multiLineSQL, stripComments, splitStatements, endDelimiter, changeSet);
}
/**
* Delimiters like "//" may span multiple tokens. Look for them and combine them
*/
private static List mergeTokens(List parsedArray, String endDelimiter) {
if (endDelimiter == null) {
return parsedArray;
}
List returnList = new ArrayList<>();
List possibleMerge = new ArrayList<>();
for (Object obj : parsedArray) {
if (possibleMerge.size() == 0) {
if ((obj instanceof String) && endDelimiter.startsWith((String) obj)) {
possibleMerge.add((String) obj);
} else {
returnList.add(obj);
}
} else {
String possibleMergeString = StringUtil.join(possibleMerge, "") + obj.toString();
if (endDelimiter.equals(possibleMergeString)) {
returnList.add(possibleMergeString);
possibleMerge.clear();
} else if (endDelimiter.startsWith(possibleMergeString)) {
possibleMerge.add(obj.toString());
} else {
returnList.addAll(possibleMerge);
returnList.add(obj);
possibleMerge.clear();
}
}
}
return returnList;
}
/**
* Returns true if the input is a delimiter in one of the popular RDBMSs. Recognized delimiters are: semicolon (;),
* a slash (as the only content) or the word GO (as the only content).
*
* @param piece the input line to test
* @param previousPiece the characters in the input stream that came before piece
* @param endDelimiter ??? (need to see this in a debugger to find out)
*/
protected static boolean isDelimiter(String piece, String previousPiece, String endDelimiter) {
if (endDelimiter == null) {
return ";".equals(piece) || (("go".equalsIgnoreCase(piece) || "/".equals(piece)) && ((previousPiece ==
null) || previousPiece.endsWith("\n")));
} else {
if (endDelimiter.length() == 1) {
if ("/".equals(endDelimiter)) {
if (Boolean.TRUE.equals(GlobalConfiguration.STRICT.getCurrentValue())) {
if (previousPiece != null) {
return previousPiece.contentEquals(endDelimiter) && piece.startsWith("\n");
}
} else if (previousPiece != null && !previousPiece.endsWith("\n")) {
//don't count /'s the are there for comments for division signs or any other use besides a / at the beginning of a line
return false;
}
}
return StringUtils.equalsIgnoreCase(piece, endDelimiter);
} else {
return StringUtils.equalsIgnoreCase(piece, endDelimiter) || (previousPiece + piece).toLowerCase().matches("[\\s\n\r]*" + endDelimiter.toLowerCase());
}
}
}
/**
* Add new lines to the input string to cause output to wrap. Optional line padding
* can be passed in for the additional lines that are created
*
* @param inputStr The string to split and wrap
* @param wrapPoint The point at which to split the lines
* @param extraLinePadding Any additional spaces to add
* @return String Output string with new lines
* @deprecated Liquibase does not wrap any console output, and instead lets the terminal handle its own wrapping.
* If you wish to use this method, consider whether its usage is truly necessary.
*/
@Deprecated
public static String wrap(final String inputStr, int wrapPoint, int extraLinePadding) {
//
// Just return
//
if (inputStr == null) {
return null;
}
int inputLineLength = inputStr.length();
int ptr = 0;
int sizeOfMatch = -1;
StringBuilder resultLine = new StringBuilder();
while (ptr < inputLineLength) {
Integer spaceToWrapAt = null;
int min = ptr + wrapPoint + 1;
Matcher matcher = spacePattern.matcher(inputStr.substring(ptr, Math.min(min, inputLineLength)));
if (matcher.find()) {
int matcherStart = matcher.start();
if (matcherStart == 0) {
sizeOfMatch = matcher.end();
if (sizeOfMatch != 0) {
ptr += sizeOfMatch;
continue;
}
ptr += 1;
}
spaceToWrapAt = matcherStart + ptr;
}
//
// Break because we do not have enough characters left to need to wrap
//
if (inputLineLength - ptr <= wrapPoint) {
break;
}
//
// Advance through all the spaces
//
while (matcher.find()) {
spaceToWrapAt = matcher.start() + ptr;
}
if (spaceToWrapAt != null && spaceToWrapAt >= ptr) {
resultLine.append(inputStr, ptr, spaceToWrapAt);
resultLine.append(System.lineSeparator());
for (int i = 0; i < extraLinePadding; i++) {
resultLine.append(" ");
}
ptr = spaceToWrapAt + 1;
} else {
matcher = spacePattern.matcher(inputStr.substring(ptr + wrapPoint));
if (matcher.find()) {
int matcherStart = matcher.start();
sizeOfMatch = matcher.end() - matcherStart;
spaceToWrapAt = matcherStart + ptr + wrapPoint;
}
if (sizeOfMatch == 0 && ptr != 0) {
ptr--;
}
if (spaceToWrapAt != null && spaceToWrapAt >= 0) {
resultLine.append(inputStr, ptr, spaceToWrapAt);
resultLine.append(System.lineSeparator());
for (int i = 0; i < extraLinePadding; i++) {
resultLine.append(" ");
}
ptr = spaceToWrapAt + 1;
} else {
resultLine.append(inputStr, ptr, inputStr.length());
ptr = inputLineLength;
sizeOfMatch = -1;
}
}
}
if (sizeOfMatch == 0 && ptr < inputLineLength) {
ptr--;
}
//
// Add the rest
//
resultLine.append(inputStr, ptr, inputLineLength);
return resultLine.toString();
}
/**
* Splits a candidate multi-line SQL statement along ;'s and "go"'s.
*/
public static String[] splitSQL(String multiLineSQL, String endDelimiter) {
return splitSQL(multiLineSQL, endDelimiter, null);
}
/**
* Splits a candidate multi-line SQL statement along ;'s and "go"'s.
*
* @param changeSet the changeset associated with the sql being parsed
*/
public static String[] splitSQL(String multiLineSQL, String endDelimiter, ChangeSet changeSet) {
return processMultiLineSQL(multiLineSQL, false, true, endDelimiter, changeSet);
}
/**
* Searches through a String which contains SQL code and strips out
* any comments that are between \/**\/ or anything that matches
* SP--SP\n (to support the ANSI standard commenting of --
* at the end of a line).
*
* @return The String without the comments in
*/
public static String stripComments(String multiLineSQL) {
return stripComments(multiLineSQL, null);
}
/**
* Searches through a String which contains SQL code and strips out
* any comments that are between \/**\/ or anything that matches
* SP--SP\n (to support the ANSI standard commenting of --
* at the end of a line).
*
* @param changeSet the changeset associated with the sql being parsed
* @return The String without the comments in
*/
public static String stripComments(String multiLineSQL, ChangeSet changeSet) {
if (StringUtils.isEmpty(multiLineSQL)) {
return multiLineSQL;
}
SqlParserFactory sqlParserFactory = Scope.getCurrentScope().getSingleton(SqlParserFactory.class);
LiquibaseSqlParser sqlParser = sqlParserFactory.getSqlParser();
return sqlParser.parse(multiLineSQL, true, false, changeSet).toString().trim();
}
public static String join(Object[] array, String delimiter, StringUtilFormatter formatter) {
if (array == null) {
return null;
}
return join(Arrays.asList(array), delimiter, formatter);
}
public static String join(String[] array, String delimiter) {
if (array == null) {
return null;
}
return join(Arrays.asList(array), delimiter);
}
public static String join(Collection collection, String delimiter) {
return join(collection, delimiter, new ToStringFormatter());
}
public static String join(Collection collection, String delimiter, StringUtilFormatter formatter) {
if (collection == null) {
return null;
}
if (collection.isEmpty()) {
return "";
}
StringBuilder buffer = new StringBuilder();
for (Object val : collection) {
buffer.append(formatter.toString(val)).append(delimiter);
}
String returnString = buffer.toString();
return returnString.substring(0, returnString.length() - delimiter.length());
}
public static String join(Collection collection, String delimiter, StringUtilFormatter formatter, boolean sorted) {
if (sorted) {
TreeSet sortedSet = new TreeSet<>();
for (Object obj : collection) {
sortedSet.add(formatter.toString(obj));
}
return join(sortedSet, delimiter);
}
return join(collection, delimiter, formatter);
}
public static String join(Collection collection, String delimiter, boolean sorted) {
if (sorted) {
return join(new TreeSet<>(collection), delimiter);
} else {
return join(collection, delimiter);
}
}
public static String join(Map map, String delimiter) {
return join(map, delimiter, new ToStringFormatter());
}
public static String join(Map map, String delimiter, StringUtilFormatter formatter) {
List list = new ArrayList<>();
for (Map.Entry entry : (Set) map.entrySet()) {
list.add(entry.getKey().toString() + "=" + formatter.toString(entry.getValue()));
}
return join(list, delimiter);
}
public static String join(ExtensibleObject extensibleObject, String delimiter) {
return join(extensibleObject, delimiter, new ToStringFormatter());
}
public static String join(ExtensibleObject extensibleObject, String delimiter, StringUtilFormatter formatter) {
List list = new ArrayList<>();
for (String attribute : new TreeSet<>(extensibleObject.getAttributes())) {
String formattedValue = formatter.toString(extensibleObject.get(attribute, Object.class));
if (formattedValue != null) {
list.add(attribute + "=" + formattedValue);
}
}
return join(list, delimiter);
}
public static List splitAndTrim(String s, String regex) {
if (s == null) {
return null;
}
List returnList = new ArrayList<>();
for (String string : s.split(regex)) {
returnList.add(string.trim());
}
return returnList;
}
/**
* @deprecated use {@link StringUtils#repeat(String, int)} instead
*/
@Deprecated
public static String repeat(String string, int times) {
return StringUtils.repeat(string, times);
}
/**
* @deprecated use {@link StringUtils#join(Object[], String)} instead
*/
@Deprecated
public static String join(Integer[] array, String delimiter) {
return StringUtils.join(array, delimiter);
}
/**
* @deprecated use {@link StringUtils#join(int[], char)} instead
*/
@Deprecated
public static String join(int[] array, String delimiter) {
return StringUtils.join(ArrayUtils.toObject(array), delimiter);
}
public static String indent(String string) {
return indent(string, 4);
}
public static String indent(String string, int padding) {
if (string == null) {
return null;
}
String pad = StringUtil.repeat(" ", padding);
return pad + (string.replaceAll("\n", "\n" + pad));
}
/**
* @deprecated use {@link StringUtils#uncapitalize(String)} instead
*/
@Deprecated
public static String lowerCaseFirst(String string) {
return StringUtils.uncapitalize(string);
}
/**
* @deprecated use {@link StringUtils#capitalize(String)} instead
*/
@Deprecated
public static String upperCaseFirst(String string) {
return StringUtils.capitalize(string);
}
public static boolean hasUpperCase(String string) {
if (string == null) {
return false;
}
return upperCasePattern.matcher(string).matches();
}
public static boolean hasLowerCase(String string) {
if (string == null) {
return false;
}
return lowerCasePattern.matcher(string).matches();
}
public static String standardizeLineEndings(String string) {
if (string == null) {
return null;
}
return string.replace("\r\n", "\n").replace("\r", "\n");
}
public static boolean isAscii(String string) {
if (string == null) {
return true;
}
for (char c : string.toCharArray()) {
if (!isAscii(c)) {
return false;
}
}
return true;
}
/**
* Returns true if ch is a "7-bit-clean" ASCII character (ordinal number < 128).
*
* @param ch the character to test
* @return true if 7 bit-clean, false otherwise.
* @deprecated use {@link CharUtils#isAscii(char)} instead
*/
@Deprecated
public static boolean isAscii(char ch) {
return CharUtils.isAscii(ch);
}
public static String escapeHtml(String str) {
if (str == null) {
return null;
}
StringBuilder out = new StringBuilder();
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
if (c > 0x7F) {
out.append("");
out.append(Integer.toString(c, 10));
out.append(';');
} else {
out.append(c);
}
}
return out.toString();
}
/**
* Adds spaces to the right of the input value until the string has reached the given length. Nothing is done
* if the string already has the given length or if the string is even longer.
*
* @param value The string to pad (if necessary)
* @param length the desired length
* @return the input string, padded if necessary.
*/
public static String pad(String value, int length) {
value = StringUtil.trimToEmpty(value);
if (value.length() >= length) {
return value;
}
return value + StringUtil.repeat(" ", length - value.length());
}
/**
* Adds spaces to the left of the input value until the string has reached the given length. Nothing is done
* if the string already has the given length or if the string is even longer.
*
* @param value The string to pad (if necessary)
* @param length the desired length
* @return the input string, padded if necessary.
*/
public static String leftPad(String value, int length) {
value = StringUtil.trimToEmpty(value);
if (value.length() >= length) {
return value;
}
return StringUtil.repeat(" ", length - value.length()) + value;
}
/**
*
* Returns true if the input string contains the specified value
*
* @param value String to be checked
* @param containsValue String to look for
* @return true if String contains the value
* @deprecated use {@link StringUtils#contains(CharSequence, CharSequence)} instead
*/
@Deprecated
public static boolean contains(String value, String containsValue) {
return StringUtils.contains(value, containsValue);
}
/**
* Returns true if the input string is the empty string (null-safe).
*
* @param value String to be checked
* @return true if String is null or empty
* @deprecated use {@link StringUtils#isEmpty(CharSequence)} instead
*/
@Deprecated
public static boolean isEmpty(String value) {
return StringUtils.isEmpty(value);
}
/**
* Returns true if the input string is NOT the empty string. If the string is null, false is returned.
*
* @param value String to be checked
* @return true if string is not null and not empty (length > 0)
* @deprecated use {@link StringUtils#isNotEmpty(CharSequence)} instead
*/
@Deprecated
public static boolean isNotEmpty(String value) {
return StringUtils.isNotEmpty(value);
}
/**
* Checks whether the given value
starts with the specified startsWith
string.
*
* @param value the string to check
* @param startsWith the prefix to check for
* @return true
if value
starts with startsWith
, false
otherwise.
* Returns false
if either argument is null
.
* @deprecated use {@link StringUtils#startsWith(CharSequence, CharSequence)} instead
*/
@Deprecated
public static boolean startsWith(String value, String startsWith) {
return StringUtils.startsWith(value, startsWith);
}
/**
* Checks whether the given value
ends with the specified endsWith
string.
*
* @param value the string to check
* @param endsWith the prefix to check for
* @return true
if value
ends with endsWith
, false
otherwise.
* Returns false
if either argument is null
.
* @deprecated use {@link StringUtils#endsWith(CharSequence, CharSequence)} instead
*/
@Deprecated
public static boolean endsWith(String value, String endsWith) {
return StringUtils.endsWith(value, endsWith);
}
/**
* Returns true if the given string only consists of whitespace characters (null-safe)
*
* @param string the string to test
* @return true if the string is null or only consists of whitespaces.
*/
public static boolean isWhitespace(CharSequence string) {
if (string == null) {
return true;
}
return StringUtils.isWhitespace(string);
}
/**
* Compares a minimum version number given in string form (only the first three parts are considered) with a
* candidate version given as the three ints major, minor and patch.
*
* @param minimumVersion The minimum version that is required, given as a string with up to 3 parts, e.g. "7.4" or "9.6.3"
* @param candidateMajor the version number to be tested, major part
* @param candidateMinor the version number to be tested, minor part
* @param candidatePatch the version number to be tested, patch part
* @return true if candidateMajor.candidateMinor.candidatePatch >= minimumVersion or false if not
*/
public static boolean isMinimumVersion(String minimumVersion, int candidateMajor, int candidateMinor,
int candidatePatch) {
if (minimumVersion == null) {
return true;
}
String[] parts = minimumVersion.split("\\.", 3);
int minMajor = Integer.parseInt(parts[0]);
int minMinor = (parts.length > 1) ? Integer.parseInt(parts[1]) : 0;
int minPatch = (parts.length > 2) ? Integer.parseInt(parts[2]) : 0;
if (minMajor > candidateMajor) {
return false;
}
if ((minMajor == candidateMajor) && (minMinor > candidateMinor)) {
return false;
}
return !((minMajor == candidateMajor) && (minMinor == candidateMinor) && (minPatch > candidatePatch));
}
public static String limitSize(String string, int maxLength) {
if (string == null) {
return null;
}
if (string.length() > maxLength) {
return string.substring(0, maxLength - 3) + "...";
}
return string;
}
/**
* Produce a random identifier of the given length, consisting only of uppercase letters.
*
* @param len desired length of the string
* @return an identifier of the desired length
* @deprecated use {@link #randomIdentifier}
*/
@Deprecated
public static String randomIdentifer(int len) {
return randomIdentifier(len);
}
/**
* Produce a random identifier of the given length, consisting only of uppercase letters.
*
* @param len desired length of the string
* @return an identifier of the desired length
*/
public static String randomIdentifier(int len) {
final String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++)
sb.append(AB.charAt(ThreadLocalRandom.current().nextInt(AB.length())));
return sb.toString();
}
/**
* Converts a camelCase string to a kabob-case one
*/
public static String toKabobCase(String string) {
if (string == null) {
return null;
}
int length = string.length();
if (length == 1) {
return string;
}
StringBuilder outString = new StringBuilder(length);
char[] charString = string.toCharArray();
for (int i = 0; i < charString.length; i++) {
char letter = charString[i];
if (i == 0) {
outString.append(Character.toLowerCase(letter));
continue;
}
if (Character.isUpperCase(letter)) {
outString.append('-').append(Character.toLowerCase(letter));
} else {
outString.append(letter);
}
}
return outString.toString();
}
/**
* Converts a kabob-case or underscore_case string to a camel-case one
*/
public static String toCamelCase(String string) {
if (string == null) {
return null;
}
StringBuilder outString = new StringBuilder();
char[] charString = string.toCharArray();
boolean uppercaseNext = false;
for (char letter : charString) {
if (letter == '-' || letter == '_') {
uppercaseNext = true;
} else {
if (uppercaseNext) {
outString.append(Character.toUpperCase(letter));
uppercaseNext = false;
} else {
outString.append(letter);
}
}
}
return outString.toString();
}
public interface StringUtilFormatter {
String toString(Type obj);
}
public static class ToStringFormatter implements StringUtilFormatter {
private final boolean shouldLowercase;
public ToStringFormatter() {
this(false);
}
public ToStringFormatter(boolean shouldLowercase) {
this.shouldLowercase = shouldLowercase;
}
@Override
public String toString(Object obj) {
if (obj == null) {
return null;
}
String string = obj.toString();
if (shouldLowercase) {
string = string.toLowerCase();
}
return string;
}
}
public static class DefaultFormatter implements StringUtilFormatter {
@Override
public String toString(Object obj) {
if (obj == null) {
return null;
} else if (obj instanceof Class) {
return ((Class>) obj).getName();
} else if (obj instanceof Object[]) {
if (((Object[]) obj).length == 0) {
return null;
} else {
return "[" + StringUtil.join((Object[]) obj, ", ", this) + "]";
}
} else if (obj instanceof Collection) {
if (((Collection>) obj).size() == 0) {
return null;
} else {
return "[" + StringUtil.join((Collection) obj, ", ", this) + "]";
}
}
return obj.toString();
}
}
/**
* Returns if two strings are equal, ignoring:
*
* case (uppercase/lowercase)
* difference between null, and empty string, and a string that only has spaces
*
*
* @param s1 the first String to compare (or null)
* @param s2 the second String to compare (or null)
* @return true if the Strings are equal by the above criteria, false in all other cases
*/
public static boolean equalsIgnoreCaseAndEmpty(String s1, String s2) {
String clean1 = trimToNull(s1);
String clean2 = trimToNull(s2);
if (clean1 == null && clean2 == null) {
return true;
}
return StringUtils.equalsIgnoreCase(s1, s2);
}
/**
* Trims {@link Character#isWhitespace(char) whitespace} characters from the
* end of specified string
*
* @param string String to trim
* @return new String without the whitespace at the end
*/
public static String trimRight(String string) {
if (string == null) {
return null;
}
int i = string.length() - 1;
while (i >= 0 && Character.isWhitespace(string.charAt(i))) {
i--;
}
return string.substring(0, i + 1);
}
/**
* Retrieves the last block comment in a SQL string, if any.
*
* @param sqlString the SQL string to search for the last block comment
* @return the last block comment in the SQL string, or {@code null} if none was found
*/
public static String getLastBlockComment(String sqlString) {
if (isEmpty(sqlString) || sqlString.length() < 4) {
return null;
}
String reversedString = StringUtils.reverse(sqlString);
int idxClosingLastChar = -1, idxOpeningFirstChar = -1;
for (int i = 0; i < reversedString.length(); i++) {
if (idxClosingLastChar < 0) {
// we have not found the start of the pair (reversed) yet)
char c = reversedString.charAt(i);
if (c == '/') {
// check the second one
char s = reversedString.charAt(i + 1);
if (s == '*') {
idxClosingLastChar = i;
}
} else if (!Character.isWhitespace(c)) {
// does not look like it ends with block comment, return null
return null;
}
} else {
// look for closing pair (reversed)
char c = reversedString.charAt(i);
if (c == '/') {
// check the previous one
char s = reversedString.charAt(i - 1);
char e = reversedString.charAt(i + 1);
// if it was not escaped
if (s == '*' && e != '\\') {
idxOpeningFirstChar = i;
break;
}
}
}
}
// reverse the index to get the start of the last comment block
int idxOfLastBlockComment = sqlString.length() - (idxOpeningFirstChar + 1);
return sqlString.substring(idxOfLastBlockComment);
}
/**
* Returns the last line comment from a given SQL string, if there is one.
*
* @param sqlString the SQL string to search
* @return the last line comment from the SQL string, or {@code null} if there is no line comment
*/
public static String getLastLineComment(String sqlString) {
if (isEmpty(sqlString) || sqlString.length() < 2) {
return null;
}
boolean startOfNewLine = false;
int idxOfDoubleDash = -1;
for (int i = 0; i < sqlString.trim().length() - 1; i++) {
char c = sqlString.charAt(i);
// we have not found the start of the line comment yet
if (c == '-') {
// check the next one
char s = sqlString.charAt(i + 1);
if (s == '-') {
if (idxOfDoubleDash < 0) {
idxOfDoubleDash = i;
}
startOfNewLine = false;
}
} else if (!Character.isWhitespace(c)) {
if (startOfNewLine) {
// new line started and we found some other character, reset the index,
idxOfDoubleDash = -1;
}
} else if (c == '\r' || c == '\n') {
// new line found
startOfNewLine = true;
idxOfDoubleDash = -1;
}
}
if (idxOfDoubleDash < 0) {
return null;
}
return sqlString.substring(idxOfDoubleDash);
}
/**
* Strips the comments and white spaces from the end of given SQL string.
*
* @param sqlString the SQL string to strip
* @return the stripped SQL string
*/
public static String stripSqlCommentsAndWhitespacesFromTheEnd(String sqlString) {
if (isEmpty(sqlString)) {
return sqlString;
}
StringBuilder str = new StringBuilder(sqlString);
boolean strModified = true;
while (strModified) {
strModified = false;
// first check for last block comment
// since line comments could be inside block comments, we want to
// remove them first.
String lastBlockComment = getLastBlockComment(str.toString());
if (lastBlockComment != null && !lastBlockComment.isEmpty()) {
str.setLength(str.length() - lastBlockComment.length());
// we just modified the end of the string,
// do another loop to check for next block or line comments
strModified = true;
}
// now check for the line comments
String lastLineComment = getLastLineComment(str.toString());
if (lastLineComment != null && !lastLineComment.isEmpty()) {
str.setLength(str.length() - lastLineComment.length());
// we just modified the end of the string,
// do another loop to check for next block or line comments
strModified = true;
}
}
return trimRight(str.toString());
}
/**
* Concatenates the addition string to the baseString string, adjusting the case of "addition" to match the base string.
* If the string is all caps, append addition in all caps. If all lower case, append in all lower case. If baseString is mixed case, make no changes to addition.
*/
public static String concatConsistentCase(String baseString, String addition) {
boolean hasLowerCase = hasLowerCase(baseString);
boolean hasUpperCase = hasUpperCase(baseString);
if ((hasLowerCase && hasUpperCase) || (!hasLowerCase && !hasUpperCase)) { //mixed case || no letters
return baseString + addition;
} else if (hasLowerCase) {
return baseString + addition.toLowerCase();
} else {
return baseString + addition.toUpperCase();
}
}
public static String stripEnclosingQuotes(String string) {
if (string.length() > 1 &&
(string.charAt(0) == '"' || string.charAt(0) == '\'') &&
string.charAt(0) == string.charAt(string.length() - 1)) {
return string.substring(1, string.length() - 1);
} else {
return string;
}
}
/**
* Check whether the value is 'null' (case insensitive)
*/
public static boolean equalsWordNull(String value) {
return "NULL".equalsIgnoreCase(value);
}
/**
* Splits a camel-case string into words based on the came casing.
*
* @param str the String to split, may be {@code null}
* @return an array of parsed Strings, {@code null} if null String input
* @deprecated use {@link StringUtils#splitByCharacterTypeCamelCase(String)} instead
*/
@Deprecated
public static String[] splitCamelCase(final String str) {
return StringUtils.splitByCharacterTypeCamelCase(str);
}
public static byte[] getBytesWithEncoding(String string) {
if (string == null) {
return null;
}
String encoding = null;
try {
encoding = GlobalConfiguration.OUTPUT_FILE_ENCODING.getCurrentConfiguredValue().getValue();
if (encoding != null) {
return string.getBytes(encoding);
}
} catch (UnsupportedEncodingException uoe) {
// Consume and fall through
Scope.getCurrentScope().getLog(StringUtil.class).warning("Error using encoding " + encoding + ": " + uoe);
}
return string.getBytes(StandardCharsets.UTF_8);
}
/**
* @param value string to process
* @return string without any whitespaces formatted to lowercase.
* @deprecated use {@link StringUtils#toRootLowerCase(String)} and {@link StringUtils#deleteWhitespace(String)} instead
*/
@Deprecated
public static String toLowerWithoutWhitespaces(String value) {
return StringUtils.toRootLowerCase(StringUtils.deleteWhitespace(value));
}
/**
*
Checks whether the char sequence is numeric by checking that all chars in the sequence are
* numbers, so (-1, 1.0 and 1F) will return false
*
* @param cs the arg to check if it is numeric
* @return true if convertible to numeric and false otherwise
* @deprecated use {@link StringUtils#isNumeric(CharSequence)} instead
*/
@Deprecated
public static boolean isNumeric(CharSequence cs) {
return StringUtils.isNumeric(cs);
}
/**
* @deprecated use {@link StringUtils#isEmpty(CharSequence)}
*/
@Deprecated
public static boolean isEmpty(CharSequence cs) {
return StringUtils.isEmpty(cs);
}
/**
* Split the input string into chunks no larger than the supplied chunkSize. If the string is shorter than the
* chunkSize, the resultant list will contain only a single entry.
*/
public static List splitToChunks(String input, int chunkSize) {
int length = input.length();
if (length < chunkSize) {
return Collections.singletonList(input);
}
List chunks = new ArrayList<>((length / chunkSize) + 1);
for (int i = 0; i < length; i += chunkSize) {
int end = Math.min(i + chunkSize, length);
String chunk = input.substring(i, end);
chunks.add(chunk);
}
return chunks;
}
}