/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.openjpa.lib.util; import java.util.ArrayList; import java.util.List; public final class StringUtil { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final Byte BYTE_ZERO = Byte.valueOf((byte) 0); private static final Character CHAR_ZERO = Character.valueOf((char) 0); private static final Double DOUBLE_ZERO = Double.valueOf(0.0d); private static final Float FLOAT_ZERO = Float.valueOf(0.0f); private static final Integer INTEGER_ZERO = Integer.valueOf(0); private static final Long LONG_ZERO = Long.valueOf(0); private static final Short SHORT_ZERO = Short.valueOf((short) 0); private StringUtil() { } /** * @return {@code true} if the given string is null or empty. */ public static boolean isEmpty(String val) { return val == null || val.isEmpty(); } public static boolean isNotEmpty(String val) { return !isEmpty(val); } /** * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p> * * <pre> * StringUtils.isBlank(null) = true * StringUtils.isBlank("") = true * StringUtils.isBlank(" ") = true * StringUtils.isBlank("bob") = false * StringUtils.isBlank(" bob ") = false * </pre> * * Ported over from Apache commons-lang3 * * @param cs the CharSequence to check, may be null * @return {@code true} if the CharSequence is null, empty or whitespace */ public static boolean isBlank(final CharSequence cs) { int strLen; if (cs == null || (strLen = cs.length()) == 0) { return true; } for (int i = 0; i < strLen; i++) { if (Character.isWhitespace(cs.charAt(i)) == false) { return false; } } return true; } /** * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> * * <pre> * StringUtils.isNotBlank(null) = false * StringUtils.isNotBlank("") = false * StringUtils.isNotBlank(" ") = false * StringUtils.isNotBlank("bob") = true * StringUtils.isNotBlank(" bob ") = true * </pre> * * Ported over from Apache commons-lang3 * * @param cs the CharSequence to check, may be null * @return {@code true} if the CharSequence is not empty and not null and not whitespace */ public static boolean isNotBlank(final CharSequence cs) { return !isBlank(cs); } /** * @param val the string to search in * @param charToSearchFor the character to search for * @return {@code true} if the charToSearchFor is contained in the String val */ public static boolean contains(String val, char charToSearchFor) { return val != null && val.indexOf(charToSearchFor) > -1; } public static boolean equalsIgnoreCase(String str1, String str2) { if (str1 == null || str2 == null) { return str1 == str2; } else if (str1 == str2) { return true; } return str1.equalsIgnoreCase(str2); } /** * Splits the given string on the given token. Follows the semantics * of the Java 1.4 {@link String#split(String, int)} method, but does * not treat the given token as a regular expression. */ public static String[] split(String str, String token, int max) { if (str == null || str.length() == 0) { return EMPTY_STRING_ARRAY; } if (token == null || token.length() == 0) { throw new IllegalArgumentException("token: [" + token + "]"); } // split on token List<String> ret = new ArrayList<>(); int start = 0; int len = str.length(); int tlen = token.length(); int pos = 0; while (pos != -1) { pos = str.indexOf(token, start); if (pos != -1) { ret.add(str.substring(start, pos)); start = pos + tlen; } } if (start < len) { ret.add(str.substring(start)); } else if (start == len) { ret.add(""); } // now take max into account; this isn't the most efficient way // of doing things since we split the maximum number of times // regardless of the given parameters, but it makes things easy if (max == 0) { int size = ret.size(); // discard any trailing empty splits while (ret.get(--size).isEmpty()) { ret.remove(size); } } else if (max > 0 && ret.size() > max) { // move all splits over max into the last split StringBuilder sb = new StringBuilder(256); sb.append(ret.get(max - 1)); ret.remove(max - 1); while (ret.size() >= max) { sb.append(token).append(ret.get(max - 1)); ret.remove(max - 1); } ret.add(sb.toString()); } return ret.toArray(new String[ret.size()]); } /** * Replace all instances of <code>from</code> in <code>str</code> * with <code>to</code>. * * @param str the candidate string to replace * @param from the token to replace * @param to the new token * @return the string with all the replacements made */ public static String replace(String str, String from, String to) { if (from.equals(to)) { return str; } String[] split = split(str, from, Integer.MAX_VALUE); return join(split, to); } /** * Null-safe {@link String#trim()} */ public static String trim(final String str) { return str == null ? null : str.trim(); } /** * @return the trimmed string str or {@code null} if the trimmed string would be empty. */ public static String trimToNull(String str) { if (str == null || str.isEmpty()) { return null; } str = str.trim(); if (str.isEmpty()) { return null; } return str; } public static String join(Object[] values, String joinToken) { if (values == null) { return null; } if (values.length == 0) { return ""; } if (values.length == 1) { return values[0].toString(); } if (joinToken == null) { joinToken = "null"; // backward compat with commons-lang StringUtils... } StringBuilder sb = new StringBuilder(values.length * (16 + joinToken.length())); sb.append(values[0]); for (int i = 1; i < values.length; i++) { sb.append(joinToken).append(values[i]); } return sb.toString(); } /** * Parse the given * * @param val value to parse * @param type the target type of the the parsed value * @return the converted value */ public static <T> T parse(String val, Class<T> type) { if (type == null) { throw new NullPointerException("target type must not be null"); } // handle primitives if (type == byte.class) { return (T) (val == null ? BYTE_ZERO : Byte.valueOf(val)); } if (type == char.class) { return (T) (val == null ? CHAR_ZERO : parseCharString(val)); } if (type == double.class) { return (T) (val == null ? DOUBLE_ZERO : Double.valueOf(val)); } if (type == float.class) { return (T) (val == null ? FLOAT_ZERO : Float.valueOf(val)); } if (type == int.class) { return (T) (val == null ? INTEGER_ZERO : Integer.valueOf(val)); } if (type == long.class) { return (T) (val == null ? LONG_ZERO : Long.valueOf(val)); } if (type == short.class) { return (T) (val == null ? SHORT_ZERO : Short.valueOf(val)); } if (type == boolean.class) { return (T) (val == null ? Boolean.FALSE : Boolean.valueOf(val)); } if (type == void.class) { throw new IllegalStateException("Cannot parse void type"); } // handle wrapper types if (type == Byte.class) { return (T) (val == null ? null : Byte.valueOf(val)); } if (type == Character.class) { return (T) (val == null ? null : parseCharString(val)); } if (type == Double.class) { return (T) (val == null ? null : Double.valueOf(val)); } if (type == Float.class) { return (T) (val == null ? null : Float.valueOf(val)); } if (type == Integer.class) { return (T) (val == null ? null : Integer.valueOf(val)); } if (type == Long.class) { return (T) (val == null ? null : Long.valueOf(val)); } if (type == Short.class) { return (T) (val == null ? null : Short.valueOf(val)); } if (type == Boolean.class) { return (T) (val == null ? null : Boolean.valueOf(val)); } throw new IllegalArgumentException("Unsupported type: " + type.getCanonicalName()); } /** * <p>Capitalizes a String changing the first letter to title case as * per {@link Character#toTitleCase(char)}. No other letters are changed.</p> * * * <pre> * StringUtil.capitalize(null) = null * StringUtil.capitalize("") = "" * StringUtil.capitalize("cat") = "Cat" * StringUtil.capitalize("cAt") = "CAt" * </pre> * * Ported over from Apache commons-lang3 * * @param str the String to capitalize, may be null * @return the capitalized String, {@code null} if null String input * @see #uncapitalize(String) */ public static String capitalize(final String str) { int strLen; if (str == null || (strLen = str.length()) == 0) { return str; } final char firstChar = str.charAt(0); if (Character.isTitleCase(firstChar)) { // already capitalized return str; } return new StringBuilder(strLen) .append(Character.toTitleCase(firstChar)) .append(str.substring(1)) .toString(); } /** * <p>Uncapitalizes a String changing the first letter to title case as * per {@link Character#toLowerCase(char)}. No other letters are changed.</p> * * <pre> * StringUtil.uncapitalize(null) = null * StringUtil.uncapitalize("") = "" * StringUtil.uncapitalize("Cat") = "cat" * StringUtil.uncapitalize("CAT") = "cAT" * </pre> * * Ported over from Apache commons-lang3 * * @param str the String to uncapitalize, may be null * @return the uncapitalized String, {@code null} if null String input * @see #capitalize(String) */ public static String uncapitalize(final String str) { int strLen; if (str == null || (strLen = str.length()) == 0) { return str; } final char firstChar = str.charAt(0); if (Character.isLowerCase(firstChar)) { // already uncapitalized return str; } return new StringBuilder(strLen) .append(Character.toLowerCase(firstChar)) .append(str.substring(1)) .toString(); } public static boolean endsWithIgnoreCase(String str, String suffix) { if (str == null || suffix == null) { return str == null && suffix == null; } int strlen = str.length(); if (suffix.length() > strlen) { return false; } return str.substring(str.length() - suffix.length(), strlen).equalsIgnoreCase(suffix); } /** * <p>Strips any of a set of characters from the end of a String.</p> * * <p>A {@code null} input String returns {@code null}. * An empty string ("") input returns the empty string.</p> * * <p>If the stripChars String is {@code null}, whitespace is * stripped as defined by {@link Character#isWhitespace(char)}.</p> * * <pre> * StringUtils.stripEnd(null, *) = null * StringUtils.stripEnd("", *) = "" * StringUtils.stripEnd("abc", "") = "abc" * StringUtils.stripEnd("abc", null) = "abc" * StringUtils.stripEnd(" abc", null) = " abc" * StringUtils.stripEnd("abc ", null) = "abc" * StringUtils.stripEnd(" abc ", null) = " abc" * StringUtils.stripEnd(" abcyx", "xyz") = " abc" * StringUtils.stripEnd("120.00", ".0") = "12" * </pre> * * Ported over from Apache commons-lang3 * * @param str the String to remove characters from, may be null * @param stripChars the set of characters to remove, null treated as whitespace * @return the stripped String, {@code null} if null String input */ public static String stripEnd(final String str, final String stripChars) { int end; if (str == null || (end = str.length()) == 0) { return str; } if (stripChars == null) { while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { end--; } } else if (stripChars.isEmpty()) { return str; } else { while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != -1) { end--; } } return str.substring(0, end); } private static Character parseCharString(String val) { if (val.length() == 0) { return Character.valueOf((char) 0); } if (val.length() == 1) { return val.charAt(0); } throw new IllegalArgumentException("'" + val + "' is longer than one character."); } }