/* * Copyright 2011-2014 Eric F. Savage, code@efsavage.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.ajah.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * Utilities for dealing with Strings. * * @author Eric F. Savage <code@efsavage.com> */ public class StringUtils { /** * The Non-breaking space character. */ public static final char NBSP = (char) 160; /** * Shorthand method for passing varargs to methods requiring arrays. * * @param strings * The array of strings. * @return The same object, but cast as an array automatically by Java. */ public static String[] asArray(final String... strings) { return strings; } /** * Capitalizes first letter of a String. * * @see Character#toTitleCase(char) * @param string * String to capitalized * @return String, capitalized, may be null if null is passed in. */ public static String capitalize(final String string) { if (StringUtils.isBlank(string)) { return string; } return Character.toTitleCase(string.charAt(0)) + string.substring(1); } /** * Performs a {@link String#split(String)} but {@link String#trim()}s all * values and omits blank values. * * @param string * The string to split. If null, an empty list will be returned. * @param regex * The pattern to split on. This should not contain whitespace. * @return List of trimmed, non-blank tokens. */ public static List<String> cleanSplit(final String string, final String regex) { if (isBlank(string)) { return Collections.emptyList(); } final List<String> list = new ArrayList<>(); for (final String token : string.split(regex)) { if (!isBlank(token)) { list.add(token.trim()); } } return list; } /** * Checks a string with {@link String#endsWith(String)} against an array of * candidate strings. * * @param string * The string to check. * @param suffixes * The array of suffixes to use. * @return true if the string ends with any of the suffixes, otherwise * false. */ public static boolean endsWith(final String string, final String[] suffixes) { if (isBlank(string) || suffixes == null || suffixes.length == 0) { return false; } for (final String suffix : suffixes) { if (string.endsWith(suffix)) { return true; } } return false; } /** * Looks for null or empty strings. * * @param string * String to be tested, may be null * @return true if string is null or zero-length */ public static boolean isBlank(final String string) { if (string == null) { return true; } if (string.indexOf(NBSP) >= 0) { return isBlank(string.replace(NBSP, ' ')); } return string.length() < 1 || string.trim().length() < 1; } /** * Joins a list of strings, separating them by delimeter if they are not * blank. * * @param delimiter * The delimiter to use between strings. * @param strings * The list of strings to join. * @return A joined list of strings, may be empty or null; */ public static String join(final String delimiter, final Collection<String> strings) { if (strings == null || strings.size() < 1) { return null; } StringBuilder retVal = null; for (final String string : strings) { if (StringUtils.isBlank(string)) { continue; } if (retVal == null) { retVal = new StringBuilder(); } else { retVal.append(delimiter); } retVal.append(string); } return retVal == null ? null : retVal.toString(); } /** * Joins a list of ints, separating them by delimiter if they are not blank. * * @param delimiter * The delimiter to use between numbers. * @param numbers * The list of numbers to join. * @return A joined list of numbers, may be empty or null; */ public static String join(final String delimiter, final int... numbers) { if (numbers == null || numbers.length < 1) { return null; } StringBuilder retVal = null; for (final int number : numbers) { if (retVal == null) { retVal = new StringBuilder(); } else { retVal.append(delimiter); } retVal.append(number); } return retVal == null ? null : retVal.toString(); } /** * Joins a list of strings, separating them by delimeter if they are not * blank. * * @param delimiter * The delimiter to use between strings. * @param strings * The list of strings to join. * @return A joined list of strings, may be empty or null; */ public static String join(final String delimiter, final String... strings) { if (strings == null || strings.length < 1) { return null; } StringBuilder retVal = null; for (final String string : strings) { if (StringUtils.isBlank(string)) { continue; } if (retVal == null) { retVal = new StringBuilder(); } else { retVal.append(delimiter); } retVal.append(string); } return retVal == null ? null : retVal.toString(); } /** * Calls {@link #join(String[], String)} with a comma for a delimiter. Array * of Strings, may be empty or null. * * @param array * The array to be joined, may be empty or null. * @return The joined array. If array was null or empty or contained only * null or empty Strings, returns null. */ public static String join(final String[] array) { return join(array, ","); } /** * Joins an array of Strings into a single String with the specified * delimeter. * * @param array * Array of Strings, may be empty or null. * @param delimiter * The delimiter to put between the joined Strings, may be empty * or null. * @return The joined array with delimiter in between joined Strings. If * array was null or empty or contained only null or empty Strings, * returns null. */ @Deprecated public static String join(final String[] array, final String delimiter) { if (array == null || array.length == 0) { return null; } else if (array.length == 1) { return array[0]; } final StringBuffer buf = new StringBuffer(); boolean first = delimiter != null; for (int i = 0; i < array.length; i++) { if (!StringUtils.isBlank(array[i])) { if (!first) { buf.append(delimiter); } else { first = false; } buf.append(array[i]); } } if (buf.length() > 0) { return buf.toString(); } return null; } /** * Returns leftmost characters of a string. * * @param string * String to be chopped, may be null. * @param length * The maximum length of the string to return. * @return The leftmost characters of a string. If the string was null, or * shorter than the specified lenght, the original string will be * returned. */ public static String left(final String string, final int length) { if (string == null || string.length() < length) { return string; } return string.substring(0, length); } /** * Returns null if the supplied string is null or empty. * * @param string * The string to test. * @return null if the supplied string is null or empty, otherwise returns * the original string. */ public static String nullIfEmpty(final String string) { if (string == null || string.length() == 0) { return null; } return string; } /** * Returns rightmost characters of a string. * * @param string * String to be chopped, may be null. * @param length * The maximum length of the string to return. * @return The leftmost characters of a string. If the string was null, or * shorter than the specified lenght, the original string will be * returned. */ public static String right(final String string, final int length) { if (string == null || string.length() < length) { return string; } final int fullLength = string.length(); return string.substring(fullLength - length, fullLength); } /** * Returns the leftmost characters of a string. If the string is empty or * null or shorter than the requested length, returns the original string. * * @param string * The string to truncate. * @param chars * The number characters to truncate to. * @return A string that is no longer than the length specified. */ public static String safeLeft(final String string, final int chars) { if (StringUtils.isBlank(string) || string.length() <= chars) { return string; } return string.substring(0, chars); } /** * Returns length of string, 0 if null. * * @param string * String to be tested, may be null. * @return length of string, 0 if null. */ public static int safeLength(final String string) { return string == null ? 0 : string.length(); } /** * Returns toString() for the object passed, if it is not null, otherwise * returns null. * * @see Object#toString() * @param object * The object to check/toString() * @return object.toString() or null */ public static String safeToString(final Object object) { if (object == null) { return null; } return object.toString(); } /** * Trims a string, accepting null values. If a null value is passed, returns * an empty string. Useful for concatenating so you don't get literal "null" * strings. * * @param string * The string to trim, may be null. * @return The trimmed string. */ public static String safeTrim(final String string) { if (string == null) { return ""; } return string.trim(); } /** * Converts camelCase text to regular text. Example: "canOfSoda" converts to * "can of soda". Source: <a href= * "http://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java" * >Stack Overflow</a> * * @param string * @return String, de-camelcased. */ public static String splitCamelCase(final String string) { return string.replaceAll(String.format("%s|%s|%s", "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])", "(?<=[A-Za-z])(?=[^A-Za-z])"), " "); } /** * Converts a string into a "clean" token suitable for URLs. It will be * converted to lowercase, have non-word characters replaced with hyphens, * and be split if it apepars to be camelcase. * * @see #splitCamelCase(String) * @param string * The string to convert. * @return The converted string. */ public static String toCleanUrlToken(final String string) { if (StringUtils.isBlank(string)) { throw new IllegalArgumentException("Non-blank string required"); } return splitCamelCase(string.trim()).toLowerCase().replaceAll("[\\W_]+", "-"); } /** * Truncates a string if it is longer than desired. * * @param string * The string to truncate. * @param maxLength * The maximum length of the string, must be greater than 1. * @return The string truncated to maxLength characters if necessary, * otherwise will return the original string, including null. */ public static String truncate(final String string, final int maxLength) { if (StringUtils.isBlank(string)) { return string; } if (maxLength < 1) { throw new IllegalArgumentException("maxLength must be greater than 0"); } if (string.length() > maxLength) { return string.substring(0, maxLength); } return string; } /** * Limits a string to a set of choices, with a default value if there is no * match. * * @param string * The string to match. * @param validStrings * The array of valid strings. * @param defaultValue * The default value if there is no match. * @return The string if it is valid, otherwise the default value. */ public static String whitelist(final String string, final String[] validStrings, final String defaultValue) { AjahUtils.requireParam(validStrings, "validStrings"); if (string == null) { return defaultValue; } for (final String validString : validStrings) { if (string.equals(validString)) { return string; } } return defaultValue; } /** * Wraps each string in a collection with another string, often quotes or * parentheses. * * @param strings * The strings to wrap. * @param wrapper * The wrapper to prepend and append. * @return A new collection of the same size, with the wrapper prepended and * appended to each member. */ public static List<String> wrap(final List<String> strings, final String wrapper) { if (strings == null) { return null; } final List<String> wrapped = new ArrayList<>(strings.size()); for (final String string : strings) { wrapped.add(wrapper + string + wrapper); } return wrapped; } }