/*
* 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.eclipse.leshan.util;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* <p>
* Operations on {@link java.lang.String} that are <code>null</code> safe.
* </p>
*
* <ul>
* <li><b>IsEmpty/IsBlank</b> - checks if a String contains text</li>
* <li><b>Trim/Strip</b> - removes leading and trailing whitespace</li>
* <li><b>Equals</b> - compares two strings null-safe</li>
* <li><b>startsWith</b> - check if a String starts with a prefix null-safe</li>
* <li><b>endsWith</b> - check if a String ends with a suffix null-safe</li>
* <li><b>IndexOf/LastIndexOf/Contains</b> - null-safe index-of checks
* <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> - index-of any of a set of Strings</li>
* <li><b>ContainsOnly/ContainsNone/ContainsAny</b> - does String contains only/none/any of these characters</li>
* <li><b>Substring/Left/Right/Mid</b> - null-safe substring extractions</li>
* <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> - substring extraction relative to other strings</li>
* <li><b>Split/Join</b> - splits a String into an array of substrings and vice versa</li>
* <li><b>Remove/Delete</b> - removes part of a String</li>
* <li><b>Replace/Overlay</b> - Searches a String and replaces one String with another</li>
* <li><b>Chomp/Chop</b> - removes the last part of a String</li>
* <li><b>LeftPad/RightPad/Center/Repeat</b> - pads a String</li>
* <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> - changes the case of a String</li>
* <li><b>CountMatches</b> - counts the number of occurrences of one String in another</li>
* <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> - checks the characters in a String</li>
* <li><b>DefaultString</b> - protects against a null input String</li>
* <li><b>Reverse/ReverseDelimited</b> - reverses a String</li>
* <li><b>Abbreviate</b> - abbreviates a string using ellipsis</li>
* <li><b>Difference</b> - compares Strings and reports on their differences</li>
* <li><b>LevensteinDistance</b> - the number of changes needed to change one String into another</li>
* </ul>
*
* <p>
* The <code>StringUtils</code> class defines certain words related to String handling.
* </p>
*
* <ul>
* <li>null - <code>null</code></li>
* <li>empty - a zero-length string (<code>""</code>)</li>
* <li>space - the space character (<code>' '</code>, char 32)</li>
* <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
* <li>trim - the characters <= 32 as in {@link String#trim()}</li>
* </ul>
*
* <p>
* <code>StringUtils</code> handles <code>null</code> input Strings quietly. That is to say that a <code>null</code>
* input will return <code>null</code>. Where a <code>boolean</code> or <code>int</code> is being returned details vary
* by method.
* </p>
*
* <p>
* A side effect of the <code>null</code> handling is that a <code>NullPointerException</code> should be considered a
* bug in <code>StringUtils</code> (except for deprecated methods).
* </p>
*
* <p>
* Methods in this class give sample code to explain their operation. The symbol <code>*</code> is used to indicate any
* input including <code>null</code>.
* </p>
*
* <p>
* #ThreadSafe#
* </p>
*
* @see java.lang.String
* @author Apache Software Foundation
* @author <a href="http://jakarta.apache.org/turbine/">Apache Jakarta Turbine</a>
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
* @author Daniel L. Rall
* @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
* @author <a href="mailto:ed@apache.org">Ed Korthof</a>
* @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
* @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
* @author Holger Krauth
* @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @author Arun Mammen Thomas
* @author Gary Gregory
* @author Phil Steitz
* @author Al Chou
* @author Michael Davey
* @author Reuben Sivan
* @author Chris Hyzer
* @author Scott Johnson
* @since 1.0
* @version $Id: StringUtils.java 1058365 2011-01-13 00:04:49Z niallp $
*/
// @Immutable
public class StringUtils {
// Equals
// -----------------------------------------------------------------------
/**
* <p>
* Compares two Strings, returning <code>true</code> if they are equal.
* </p>
*
* <p>
* <code>null</code>s are handled without exceptions. Two <code>null</code> references are considered to be equal.
* The comparison is case sensitive.
* </p>
*
* <pre>
* StringUtils.equals(null, null) = true
* StringUtils.equals(null, "abc") = false
* StringUtils.equals("abc", null) = false
* StringUtils.equals("abc", "abc") = true
* StringUtils.equals("abc", "ABC") = false
* </pre>
*
* @see java.lang.String#equals(Object)
* @param str1 the first String, may be null
* @param str2 the second String, may be null
* @return <code>true</code> if the Strings are equal, case sensitive, or both <code>null</code>
*/
public static boolean equals(String str1, String str2) {
return str1 == null ? str2 == null : str1.equals(str2);
}
/**
* <p>
* Compares two Strings, returning <code>true</code> if they are equal ignoring the case.
* </p>
*
* <p>
* <code>null</code>s are handled without exceptions. Two <code>null</code> references are considered equal.
* Comparison is case insensitive.
* </p>
*
* <pre>
* StringUtils.equalsIgnoreCase(null, null) = true
* StringUtils.equalsIgnoreCase(null, "abc") = false
* StringUtils.equalsIgnoreCase("abc", null) = false
* StringUtils.equalsIgnoreCase("abc", "abc") = true
* StringUtils.equalsIgnoreCase("abc", "ABC") = true
* </pre>
*
* @see java.lang.String#equalsIgnoreCase(String)
* @param str1 the first String, may be null
* @param str2 the second String, may be null
* @return <code>true</code> if the Strings are equal, case insensitive, or both <code>null</code>
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
}
// Empty checks
// -----------------------------------------------------------------------
/**
* <p>
* Checks if a String is empty ("") or null.
* </p>
*
* <pre>
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
* </pre>
*
* <p>
* NOTE: This method changed in Lang version 2.0. It no longer trims the String. That functionality is available in
* isBlank().
* </p>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
// Trim
// -----------------------------------------------------------------------
/**
* <p>
* Removes control characters (char <= 32) from both ends of this String, handling <code>null</code> by returning
* <code>null</code>.
* </p>
*
* <p>
* The String is trimmed using {@link String#trim()}. Trim removes start and end characters <= 32. To strip
* whitespace use {@link #strip(String)}.
* </p>
*
* <p>
* To trim your choice of characters, use the {@link #strip(String, String)} methods.
* </p>
*
* <pre>
* StringUtils.trim(null) = null
* StringUtils.trim("") = ""
* StringUtils.trim(" ") = ""
* StringUtils.trim("abc") = "abc"
* StringUtils.trim(" abc ") = "abc"
* </pre>
*
* @param str the String to be trimmed, may be null
* @return the trimmed string, <code>null</code> if null String input
*/
public static String trim(String str) {
return str == null ? null : str.trim();
}
// Remove
// -----------------------------------------------------------------------
/**
* <p>
* Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
* </p>
*
* <p>
* A <code>null</code> source string will return <code>null</code>. An empty ("") source string will return the
* empty string. A <code>null</code> search string will return the source string.
* </p>
*
* <pre>
* StringUtils.removeStart(null, *) = null
* StringUtils.removeStart("", *) = ""
* StringUtils.removeStart(*, null) = *
* StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
* StringUtils.removeStart("domain.com", "www.") = "domain.com"
* StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
* StringUtils.removeStart("abc", "") = "abc"
* </pre>
*
* @param str the source String to search, may be null
* @param remove the String to search for and remove, may be null
* @return the substring with the string removed if found, <code>null</code> if null String input
* @since 2.1
*/
public static String removeStart(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.startsWith(remove)) {
return str.substring(remove.length());
}
return str;
}
/**
* <p>
* Removes a substring only if it is at the end of a source string, otherwise returns the source string.
* </p>
*
* <p>
* A <code>null</code> source string will return <code>null</code>. An empty ("") source string will return the
* empty string. A <code>null</code> search string will return the source string.
* </p>
*
* <pre>
* StringUtils.removeEnd(null, *) = null
* StringUtils.removeEnd("", *) = ""
* StringUtils.removeEnd(*, null) = *
* StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
* StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
* StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
* StringUtils.removeEnd("abc", "") = "abc"
* </pre>
*
* @param str the source String to search, may be null
* @param remove the String to search for and remove, may be null
* @return the substring with the string removed if found, <code>null</code> if null String input
* @since 2.1
*/
public static String removeEnd(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.endsWith(remove)) {
return str.substring(0, str.length() - remove.length());
}
return str;
}
/**
* Constructs a new <code>String</code> by decoding the specified array of bytes using the given charset.
*
* @param bytes The bytes to be decoded into characters
* @param charset The {@link Charset} to encode the <code>String</code>
* @return A new <code>String</code> decoded from the specified array of bytes using the given charset, or
* <code>null</code> if the input byte array was <code>null</code>.
* @throws NullPointerException Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since
* it is required by the Java platform specification.
*/
private static String newString(final byte[] bytes, final Charset charset) {
return bytes == null ? null : new String(bytes, charset);
}
/**
* Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-8 charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-8 charset, or
* <code>null</code> if the input byte array was <code>null</code>.
* @throws NullPointerException Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since
* it is required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUtf8(final byte[] bytes) {
return newString(bytes, StandardCharsets.UTF_8);
}
/**
* Calls {@link String#getBytes(Charset)}
*
* @param string The string to encode (if null, return null).
* @param charset The {@link Charset} to encode the <code>String</code>
* @return the encoded bytes
*/
private static byte[] getBytes(final String string, final Charset charset) {
if (string == null) {
return null;
}
return string.getBytes(charset);
}
/**
* Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
* array.
*
* @param string the String to encode, may be <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @throws NullPointerException Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since
* it is required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUtf8(final String string) {
return getBytes(string, StandardCharsets.UTF_8);
}
}