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.
/**
* Copyright (C) 2006-2014 phloc systems
* http://www.phloc.com
* office[at]phloc[dot]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.phloc.commons.string;//NOPMD
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.annotation.CheckForSigned;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import com.phloc.commons.CGlobal;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.PresentForCodeCoverage;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.charset.CharsetManager;
import com.phloc.commons.collections.ArrayHelper;
import com.phloc.commons.math.MathHelper;
/**
* Generic string transformation and helper methods. If you need to modify a
* string, start looking in this class.
*
* @author Philip Helger
*/
@Immutable
public final class StringHelper
{
/**
* The constant to be returned if an String.indexOf call did not find a match!
*/
public static final int STRING_NOT_FOUND = -1;
private static final int [] s_aSizeTableInt = { 9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
Integer.MAX_VALUE };
private static final long [] s_aSizeTableLong = { 9L,
99L,
999L,
9999L,
99999L,
999999L,
9999999L,
99999999L,
999999999L,
9999999999L,
99999999999L,
999999999999L,
9999999999999L,
99999999999999L,
999999999999999L,
9999999999999999L,
99999999999999999L,
999999999999999999L,
Long.MAX_VALUE };
@PresentForCodeCoverage
@SuppressWarnings ("unused")
private static final StringHelper s_aInstance = new StringHelper ();
private StringHelper ()
{}
/**
* Check if the string is null or empty.
*
* @param aCS
* The character sequence to check. May be null.
* @return true if the string is null or empty,
* false otherwise
*/
public static boolean hasNoText (@Nullable final CharSequence aCS)
{
return aCS == null || aCS.length () == 0;
}
/**
* Check if the string is null or empty.
*
* @param sStr
* The string to check. May be null.
* @return true if the string is null or empty,
* false otherwise
*/
public static boolean hasNoText (@Nullable final String sStr)
{
return sStr == null || sStr.length () == 0;
}
/**
* Check if the string is null or empty.
*
* @param aCS
* The character sequence to check. May be null.
* @return true if the string is null or empty,
* false otherwise
*/
public static boolean isEmpty (@Nullable final CharSequence aCS)
{
return hasNoText (aCS);
}
/**
* Check if the string is null or empty.
*
* @param sStr
* The string to check. May be null.
* @return true if the string is null or empty,
* false otherwise
*/
public static boolean isEmpty (@Nullable final String sStr)
{
return hasNoText (sStr);
}
/**
* Check if the string is null or empty after trimming.
*
* @param s
* The string to check. May be null.
* @return true if the string is null or empty or
* consists only of whitespaces, false otherwise
*/
public static boolean hasNoTextAfterTrim (@Nullable final String s)
{
return s == null || s.trim ().length () == 0;
}
/**
* Check if the string is null or empty after trimming.
*
* @param s
* The string to check. May be null.
* @return true if the string is null or empty or
* consists only of whitespaces, false otherwise
*/
public static boolean isEmptyAfterTrim (@Nullable final String s)
{
return hasNoTextAfterTrim (s);
}
/**
* Check if the string contains any char.
*
* @param aCS
* The character sequence to check. May be null.
* @return true if the string contains at least one,
* false otherwise
*/
public static boolean hasText (@Nullable final CharSequence aCS)
{
return aCS != null && aCS.length () > 0;
}
/**
* Check if the string contains any char.
*
* @param sStr
* The string to check. May be null.
* @return true if the string contains at least one char,
* false otherwise
*/
public static boolean hasText (@Nullable final String sStr)
{
return sStr != null && sStr.length () > 0;
}
/**
* Check if the string contains any char.
*
* @param aCS
* The character sequence to check. May be null.
* @return true if the string contains at least one char,
* false otherwise
*/
public static boolean isNotEmpty (@Nullable final CharSequence aCS)
{
return hasText (aCS);
}
/**
* Check if the string contains any char.
*
* @param sStr
* The string to check. May be null.
* @return true if the string contains at least one char,
* false otherwise
*/
public static boolean isNotEmpty (@Nullable final String sStr)
{
return hasText (sStr);
}
/**
* Check if the string neither null nor empty after trimming.
*
* @param s
* The string to check. May be null.
* @return true if the string is neither null nor
* empty nor consists only of whitespaces, false
* otherwise
*/
public static boolean hasTextAfterTrim (@Nullable final String s)
{
return s != null && s.trim ().length () > 0;
}
/**
* Check if the string neither null nor empty after trimming.
*
* @param s
* The string to check. May be null.
* @return true if the string is neither null nor
* empty nor consists only of whitespaces, false
* otherwise
*/
public static boolean isNotEmptyAfterTrim (@Nullable final String s)
{
return hasTextAfterTrim (s);
}
@Nullable
public static String getLeadingZero (@Nullable final Byte aValue, final int nChars)
{
return aValue == null ? null : getLeadingZero (aValue.byteValue (), nChars);
}
@Nullable
public static String getLeadingZero (@Nullable final Integer aValue, final int nChars)
{
return aValue == null ? null : getLeadingZero (aValue.longValue (), nChars);
}
@Nullable
public static String getLeadingZero (@Nullable final Long aValue, final int nChars)
{
return aValue == null ? null : getLeadingZero (aValue.longValue (), nChars);
}
@Nullable
public static String getLeadingZero (@Nullable final Short aValue, final int nChars)
{
return aValue == null ? null : getLeadingZero (aValue.shortValue (), nChars);
}
@Nonnull
public static String getLeadingZero (final int nValue, final int nChars)
{
final boolean bNeg = nValue < 0;
final String sValue = Integer.toString (MathHelper.abs (nValue));
if (sValue.length () >= nChars)
return bNeg ? '-' + sValue : sValue;
// prepend '0's
final StringBuilder aSB = new StringBuilder ((bNeg ? 1 : 0) + nChars);
if (bNeg)
aSB.append ('-');
for (int i = 0; i < nChars - sValue.length (); ++i)
aSB.append ('0');
return aSB.append (sValue).toString ();
}
@Nonnull
public static String getLeadingZero (final long nValue, final int nChars)
{
final boolean bNeg = nValue < 0;
final String sValue = Long.toString (MathHelper.abs (nValue));
if (sValue.length () >= nChars)
return bNeg ? '-' + sValue : sValue;
// prepend '0's
final StringBuilder aSB = new StringBuilder ((bNeg ? 1 : 0) + nChars);
if (bNeg)
aSB.append ('-');
for (int i = 0; i < nChars - sValue.length (); ++i)
aSB.append ('0');
return aSB.append (sValue).toString ();
}
@Nonnull
public static String getLeadingZero (@Nonnull final String sValue, final int nChars)
{
final int nLen = sValue.length ();
if (nLen >= nChars)
return sValue;
// prepend '0's
final StringBuilder aSB = new StringBuilder (nChars);
for (int i = 0; i < nChars - nLen; ++i)
aSB.append ('0');
return aSB.append (sValue).toString ();
}
/**
* Get the matching hex digit.
*
* @param n
* The value to get the hex digit from. Must be between 0 and 15.
* @return The hex character (one of 0-9 or a-f), or '\0' if the value could
* not be converted
*/
public static char getHexChar (final int n)
{
return Character.forDigit (n, CGlobal.HEX_RADIX);
}
/**
* Convert a string to a byte array and than to a hexadecimal encoded string.
*
* @param sInput
* The source string. May not be null.
* @param aCharset
* The charset to use. May not be null.
* @return The String representation of the byte array of the string.
*/
@Nonnull
public static String getHexEncoded (@Nonnull final String sInput, @Nonnull final Charset aCharset)
{
ValueEnforcer.notNull (sInput, "Input");
ValueEnforcer.notNull (aCharset, "Charset");
return getHexEncoded (CharsetManager.getAsBytes (sInput, aCharset));
}
/**
* Convert a byte array to a hexadecimal encoded string.
*
* @param aInput
* The byte array to be converted to a String. May not be
* null.
* @return The String representation of the byte array.
*/
@Nonnull
public static String getHexEncoded (@Nonnull final byte [] aInput)
{
ValueEnforcer.notNull (aInput, "Input");
return getHexEncoded (aInput, 0, aInput.length);
}
/**
* Convert a byte array to a hexadecimal encoded string.
*
* @param aInput
* The byte array to be converted to a String. May not be
* null.
* @param nOfs
* Byte array offset
* @param nLen
* Number of bytes to encode
* @return The String representation of the byte array.
*/
@Nonnull
public static String getHexEncoded (@Nonnull final byte [] aInput, final int nOfs, final int nLen)
{
ValueEnforcer.isArrayOfsLen (aInput, nOfs, nLen);
final StringBuilder aSB = new StringBuilder (nLen * 2);
for (int i = nOfs; i < (nOfs + nLen); ++i)
{
final byte b = aInput[i];
final char c1 = getHexChar ((b & 0xf0) >> 4);
final char c2 = getHexChar (b & 0x0f);
aSB.append (c1).append (c2);
}
return aSB.toString ();
}
/**
* Get the decimal value of the passed hex character
*
* @param c
* The hex char to convert
* @return A value between 0 and 15, or -1 if the input character is not a hex
* char!
*/
@CheckForSigned
public static int getHexValue (@Nonnegative final char c)
{
return Character.digit (c, CGlobal.HEX_RADIX);
}
/**
* @param cHigh
* High hex part
* @param cLow
* Low hex part
* @return A value between 0 and 255, or -1 if any input character is not a
* hex char!
*/
public static int getHexByte (@Nonnegative final char cHigh, @Nonnegative final char cLow)
{
final int nHex1 = getHexValue (cHigh);
final int nHex2 = getHexValue (cLow);
return nHex1 < 0 || nHex2 < 0 ? -1 : (nHex1 << 4) | nHex2;
}
@Nonnull
public static byte [] getHexDecoded (@Nonnull final String sInput)
{
ValueEnforcer.notNull (sInput, "Input");
return getHexDecoded (sInput.toCharArray (), 0, sInput.length ());
}
@Nonnull
public static byte [] getHexDecoded (@Nonnull final char [] aInput)
{
ValueEnforcer.notNull (aInput, "Input");
return getHexDecoded (aInput, 0, aInput.length);
}
@Nonnull
public static byte [] getHexDecoded (@Nonnull final char [] aInput,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
ValueEnforcer.isArrayOfsLen (aInput, nOfs, nLen);
if ((nLen % 2) > 0)
throw new IllegalArgumentException ("Passed chars have no even length: " + nLen);
final byte [] ret = new byte [nLen / 2];
int nRetIdx = 0;
for (int i = 0; i < nLen; i += 2)
{
final char c0 = aInput[nOfs + i];
final char c1 = aInput[nOfs + i + 1];
final int nHexByte = getHexByte (c0, c1);
if (nHexByte == -1)
throw new IllegalArgumentException ("Failed to convert '" + c0 + "' or '" + c1 + "' to a hex value!");
ret[nRetIdx++] = (byte) nHexByte;
}
return ret;
}
@Nonnull
public static String getHexString (final byte nValue)
{
// Bytes are always handled unsigned
return Integer.toString (nValue & 0xff, CGlobal.HEX_RADIX);
}
@Nonnull
public static String getHexStringLeadingZero (final byte nValue, final int nDigits)
{
return getLeadingZero (getHexString (nValue), nDigits);
}
@Nonnull
public static String getHexStringLeadingZero2 (final byte nValue)
{
final String ret = getHexString (nValue);
return ret.length () >= 2 ? ret : '0' + ret;
}
@Nonnull
public static String getHexString (final int nValue)
{
return Integer.toString (nValue, CGlobal.HEX_RADIX);
}
@Nonnull
public static String getHexStringLeadingZero (final int nValue, final int nDigits)
{
if (nValue < 0)
return "-" + getLeadingZero (getHexString (-nValue), nDigits - 1);
return getLeadingZero (getHexString (nValue), nDigits);
}
@Nonnull
public static String getHexString (final long nValue)
{
return Long.toString (nValue, CGlobal.HEX_RADIX);
}
@Nonnull
public static String getHexStringLeadingZero (final long nValue, final int nDigits)
{
if (nValue < 0)
return "-" + getLeadingZero (getHexString (-nValue), nDigits - 1);
return getLeadingZero (getHexString (nValue), nDigits);
}
@Nonnull
public static String getHexString (final short nValue)
{
return Integer.toString (nValue & 0xffff, CGlobal.HEX_RADIX);
}
@Nonnull
public static String getHexStringLeadingZero (final short nValue, final int nDigits)
{
// Short are always handled unsigned
return getLeadingZero (getHexString (nValue), nDigits);
}
/**
* Get the number of leading white spaces according to
* {@link Character#isWhitespace(char)}
*
* @param s
* The string to be parsed. May be null.
* @return Always ≥ 0.
*/
@Nonnegative
public static int getLeadingWhitespaceCount (@Nullable final String s)
{
int ret = 0;
if (s != null)
{
final int nMax = s.length ();
while (ret < nMax && Character.isWhitespace (s.charAt (ret)))
++ret;
}
return ret;
}
/**
* Get the number of trailing white spaces according to
* {@link Character#isWhitespace(char)}
*
* @param s
* The string to be parsed. May be null.
* @return Always ≥ 0.
*/
@Nonnegative
public static int getTrailingWhitespaceCount (@Nullable final String s)
{
int ret = 0;
if (s != null)
{
int nLast = s.length () - 1;
while (nLast >= 0 && Character.isWhitespace (s.charAt (nLast)))
{
++ret;
--nLast;
}
}
return ret;
}
/**
* Get the number of specified chars, the passed string starts with.
*
* @param s
* The string to be parsed. May be null.
* @param c
* The char to be searched.
* @return Always ≥ 0.
*/
@Nonnegative
public static int getLeadingCharCount (@Nullable final String s, final char c)
{
int ret = 0;
if (s != null)
{
final int nMax = s.length ();
while (ret < nMax && s.charAt (ret) == c)
++ret;
}
return ret;
}
/**
* Get the number of specified chars, the passed string ends with.
*
* @param s
* The string to be parsed. May be null.
* @param c
* The char to be searched.
* @return Always ≥ 0.
*/
@Nonnegative
public static int getTrailingCharCount (@Nullable final String s, final char c)
{
int ret = 0;
if (s != null)
{
int nLast = s.length () - 1;
while (nLast >= 0 && s.charAt (nLast) == c)
{
++ret;
--nLast;
}
}
return ret;
}
/**
* Get a concatenated String from all elements of the passed container,
* without a separator. Even null elements are added.
*
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImploded (@Nullable final Iterable > aElements)
{
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
for (final Object aElement : aElements)
aSB.append (aElement);
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed container,
* separated by the specified separator string. Even null
* elements are added.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImploded (@Nonnull final String sSep, @Nullable final Iterable > aElements)
{
ValueEnforcer.notNull (sSep, "serparator");
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
{
int nIndex = 0;
for (final Object aElement : aElements)
{
if (nIndex++ > 0)
aSB.append (sSep);
aSB.append (aElement);
}
}
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed container,
* separated by the specified separator char. Even null elements
* are added.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImploded (final char cSep, @Nullable final Iterable > aElements)
{
return getImploded (Character.toString (cSep), aElements);
}
/**
* Get a concatenated String from all elements of the passed map, separated by
* the specified separator strings.
*
* @param sSepOuter
* The separator to use for separating the map entries. May not be
* null.
* @param sSepInner
* The separator to use for separating the key from the value. May not
* be null.
* @param aElements
* The map to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImploded (@Nonnull final String sSepOuter,
@Nonnull final String sSepInner,
@Nullable final Map , ?> aElements)
{
ValueEnforcer.notNull (sSepOuter, "SepOuter");
ValueEnforcer.notNull (sSepInner, "SepInner");
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
{
int nIndex = 0;
for (final Map.Entry , ?> aElement : aElements.entrySet ())
{
if (nIndex++ > 0)
aSB.append (sSepOuter);
aSB.append (aElement.getKey ()).append (sSepInner).append (aElement.getValue ());
}
}
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed map, separated by
* the specified separator chars.
*
* @param cSepOuter
* The separator to use for separating the map entries.
* @param cSepInner
* The separator to use for separating the key from the value.
* @param aElements
* The map to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImploded (final char cSepOuter, final char cSepInner, @Nullable final Map , ?> aElements)
{
return getImploded (Character.toString (cSepOuter), Character.toString (cSepInner), aElements);
}
/**
* Get a concatenated String from all elements of the passed array, without a
* separator.
*
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (@Nullable final ELEMENTTYPE... aElements)
{
if (ArrayHelper.isEmpty (aElements))
return "";
return getImploded (aElements, 0, aElements.length);
}
/**
* Get a concatenated String from all elements of the passed array, without a
* separator.
*
* @param aElements
* The container to convert. May be null or empty.
* @param nOfs
* The offset to start from.
* @param nLen
* The number of elements to implode.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (@Nullable final ELEMENTTYPE [] aElements,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
if (aElements != null)
ValueEnforcer.isArrayOfsLen (aElements, nOfs, nLen);
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
for (int i = nOfs; i < nOfs + nLen; ++i)
aSB.append (aElements[i]);
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (@Nonnull final String sSep, @Nullable final ELEMENTTYPE... aElements)
{
ValueEnforcer.notNull (sSep, "Separator");
if (ArrayHelper.isEmpty (aElements))
return "";
return getImploded (sSep, aElements, 0, aElements.length);
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator char.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (final char cSep, @Nullable final ELEMENTTYPE... aElements)
{
return getImploded (Character.toString (cSep), aElements);
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @param nOfs
* The offset to start from.
* @param nLen
* The number of elements to implode.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (@Nonnull final String sSep,
@Nullable final ELEMENTTYPE [] aElements,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
ValueEnforcer.notNull (sSep, "Separator");
if (aElements != null)
ValueEnforcer.isArrayOfsLen (aElements, nOfs, nLen);
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
{
for (int i = nOfs; i < nOfs + nLen; ++i)
{
final ELEMENTTYPE sElement = aElements[i];
if (i > nOfs)
aSB.append (sSep);
aSB.append (sElement);
}
}
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator char.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @param nOfs
* The offset to start from.
* @param nLen
* The number of elements to implode.
* @return The concatenated string.
* @param
* The type of elements to be imploded.
*/
@Nonnull
public static String getImploded (final char cSep,
@Nullable final ELEMENTTYPE [] aElements,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
return getImploded (Character.toString (cSep), aElements, nOfs, nLen);
}
/**
* Get a concatenated String from all non-null and non empty
* elements of the passed container, separated by the specified separator
* string. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (@Nonnull final String sSep, @Nullable final Iterable aElements)
{
ValueEnforcer.notNull (sSep, "Separator");
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
{
int nElementsAdded = 0;
for (final String sElement : aElements)
if (hasText (sElement))
{
if (nElementsAdded++ > 0)
aSB.append (sSep);
aSB.append (sElement);
}
}
return aSB.toString ();
}
/**
* Get a concatenated String from all non-null and non empty
* elements of the passed container, separated by the specified separator
* char. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (final char cSep, @Nullable final Iterable aElements)
{
return getImplodedNonEmpty (Character.toString (cSep), aElements);
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator string. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (@Nonnull final String sSep, @Nullable final String... aElements)
{
ValueEnforcer.notNull (sSep, "Separator");
if (ArrayHelper.isEmpty (aElements))
return "";
return getImplodedNonEmpty (sSep, aElements, 0, aElements.length);
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator char. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (final char cSep, @Nullable final String... aElements)
{
return getImplodedNonEmpty (Character.toString (cSep), aElements);
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator string. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param sSep
* The separator to use. May not be null.
* @param aElements
* The container to convert. May be null or empty.
* @param nOfs
* The offset to start from.
* @param nLen
* The number of elements to implode.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (@Nonnull final String sSep,
@Nullable final String [] aElements,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
ValueEnforcer.notNull (sSep, "Separator");
if (aElements != null)
ValueEnforcer.isArrayOfsLen (aElements, nOfs, nLen);
final StringBuilder aSB = new StringBuilder ();
if (aElements != null)
{
int nElementsAdded = 0;
for (int i = nOfs; i < nOfs + nLen; ++i)
{
final String sElement = aElements[i];
if (hasText (sElement))
{
if (nElementsAdded++ > 0)
aSB.append (sSep);
aSB.append (sElement);
}
}
}
return aSB.toString ();
}
/**
* Get a concatenated String from all elements of the passed array, separated
* by the specified separator char. This the very generic version of
* {@link #getConcatenatedOnDemand(String, String, String)} for an arbitrary
* number of elements.
*
* @param cSep
* The separator to use.
* @param aElements
* The container to convert. May be null or empty.
* @param nOfs
* The offset to start from.
* @param nLen
* The number of elements to implode.
* @return The concatenated string.
*/
@Nonnull
public static String getImplodedNonEmpty (final char cSep,
@Nullable final String [] aElements,
@Nonnegative final int nOfs,
@Nonnegative final int nLen)
{
return getImplodedNonEmpty (Character.toString (cSep), aElements, nOfs, nLen);
}
/**
* Take a concatenated String and return the passed String array of all
* elements in the passed string, using specified separator char.
*
* @param cSep
* The separator to use.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @param nMaxItems
* The maximum number of items to explode. If the passed value is <= 0
* all items are used. If max items is 1, than the result string is
* returned as is. If max items is larger than the number of elements
* found, it has no effect.
* @return The passed collection and never null.
*/
@Nonnull
public static String [] getExplodedArray (final char cSep,
@Nullable final String sElements,
@CheckForSigned final int nMaxItems)
{
if (nMaxItems == 1)
return new String [] { sElements };
if (hasNoText (sElements))
return ArrayHelper.EMPTY_STRING_ARRAY;
final int nMaxResultElements = 1 + getCharCount (sElements, cSep);
if (nMaxResultElements == 1)
{
// Separator not found
return new String [] { sElements };
}
final String [] ret = new String [nMaxItems < 1 ? nMaxResultElements : Math.min (nMaxResultElements, nMaxItems)];
// Do not use RegExPool.stringReplacePattern because of package
// dependencies
// Do not use String.split because it trims empty tokens from the end
int nStartIndex = 0;
int nMatchIndex;
int nItemsAdded = 0;
while ((nMatchIndex = sElements.indexOf (cSep, nStartIndex)) >= 0)
{
ret[nItemsAdded++] = sElements.substring (nStartIndex, nMatchIndex);
// 1 == length of separator char
nStartIndex = nMatchIndex + 1;
if (nMaxItems > 0 && nItemsAdded == nMaxItems - 1)
{
// We have exactly one item the left: the rest of the string
break;
}
}
ret[nItemsAdded++] = sElements.substring (nStartIndex);
if (nItemsAdded != ret.length)
throw new IllegalStateException ("Added " + nItemsAdded + " but expected " + ret.length);
return ret;
}
/**
* Take a concatenated String and return the passed String array of all
* elements in the passed string, using specified separator char.
*
* @param cSep
* The separator to use.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The passed collection and never null.
*/
@Nonnull
public static String [] getExplodedArray (final char cSep, @Nullable final String sElements)
{
return getExplodedArray (cSep, sElements, -1);
}
/**
* Take a concatenated String and return the passed Collection of all elements
* in the passed string, using specified separator string.
*
* @param cSep
* The separator to use.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @param nMaxItems
* The maximum number of items to explode. If the passed value is <= 0
* all items are used. If max items is 1, than the result string is
* returned as is. If max items is larger than the number of elements
* found, it has no effect.
* @param aCollection
* The non-null collection that should be filled with the
* exploded elements
* @return The passed collection and never null.
*/
@Nonnull
public static > COLLTYPE getExploded (final char cSep,
@Nullable final String sElements,
final int nMaxItems,
@Nonnull final COLLTYPE aCollection)
{
ValueEnforcer.notNull (aCollection, "Collection");
if (nMaxItems == 1)
aCollection.add (sElements);
else
if (hasText (sElements))
{
// Do not use RegExPool.stringReplacePattern because of package
// dependencies
// Do not use String.split because it trims empty tokens from the end
int nStartIndex = 0;
int nMatchIndex;
int nItemsAdded = 0;
while ((nMatchIndex = sElements.indexOf (cSep, nStartIndex)) >= 0)
{
aCollection.add (sElements.substring (nStartIndex, nMatchIndex));
// 1 == length of separator char
nStartIndex = nMatchIndex + 1;
++nItemsAdded;
if (nMaxItems > 0 && nItemsAdded == nMaxItems - 1)
{
// We have exactly one item the left: the rest of the string
break;
}
}
aCollection.add (sElements.substring (nStartIndex));
}
return aCollection;
}
/**
* Take a concatenated String and return a {@link List} of all elements in the
* passed string, using specified separator string.
*
* @param cSep
* The separator character to use.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The {@link List} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static List getExploded (final char cSep, @Nullable final String sElements)
{
return getExploded (cSep, sElements, -1);
}
/**
* Take a concatenated String and return a {@link List} of all elements in the
* passed string, using specified separator string.
*
* @param cSep
* The separator character to use.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @param nMaxItems
* The maximum number of items to explode. If the passed value is <= 0
* all items are used. If max items is 1, than the result string is
* returned as is. If max items is larger than the number of elements
* found, it has no effect.
* @return The {@link List} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static List getExploded (final char cSep, @Nullable final String sElements, final int nMaxItems)
{
return getExploded (cSep, sElements, nMaxItems, nMaxItems >= 1 ? new ArrayList (nMaxItems)
: new ArrayList ());
}
/**
* Take a concatenated String and return the passed Collection of all elements
* in the passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @param nMaxItems
* The maximum number of items to explode. If the passed value is <= 0
* all items are used. If max items is 1, than the result string is
* returned as is. If max items is larger than the number of elements
* found, it has no effect.
* @param aCollection
* The non-null collection that should be filled with the
* exploded elements
* @return The passed collection and never null.
*/
@Nonnull
public static > COLLTYPE getExploded (@Nonnull final String sSep,
@Nullable final String sElements,
final int nMaxItems,
@Nonnull final COLLTYPE aCollection)
{
ValueEnforcer.notNull (sSep, "Separator");
ValueEnforcer.notNull (aCollection, "Collection");
if (nMaxItems == 1)
aCollection.add (sElements);
else
{
// If the separator consists only of a single character, use the
// char-optimized version for better performance
// Note: do it before the "hasText (sElements)" check, because the same
// check is performed in the char version as well
if (sSep.length () == 1)
return getExploded (sSep.charAt (0), sElements, nMaxItems, aCollection);
if (hasText (sElements))
{
// Do not use RegExPool.stringReplacePattern because of package
// dependencies
// Do not use String.split because it trims empty tokens from the end
int nStartIndex = 0;
int nMatchIndex;
int nItemsAdded = 0;
while ((nMatchIndex = sElements.indexOf (sSep, nStartIndex)) >= 0)
{
aCollection.add (sElements.substring (nStartIndex, nMatchIndex));
nStartIndex = nMatchIndex + sSep.length ();
++nItemsAdded;
if (nMaxItems > 0 && nItemsAdded == nMaxItems - 1)
{
// We have exactly one item the left: the rest of the string
break;
}
}
aCollection.add (sElements.substring (nStartIndex));
}
}
return aCollection;
}
/**
* Take a concatenated String and return a {@link List} of all elements in the
* passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The {@link List} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static List getExploded (@Nonnull final String sSep, @Nullable final String sElements)
{
return getExploded (sSep, sElements, -1);
}
/**
* Take a concatenated String and return a {@link List} of all elements in the
* passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @param nMaxItems
* The maximum number of items to explode. If the passed value is <= 0
* all items are used. If max items is 1, than the result string is
* returned as is. If max items is larger than the number of elements
* found, it has no effect.
* @return The {@link List} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static List getExploded (@Nonnull final String sSep,
@Nullable final String sElements,
final int nMaxItems)
{
return getExploded (sSep, sElements, nMaxItems, nMaxItems >= 1 ? new ArrayList (nMaxItems)
: new ArrayList ());
}
/**
* Take a concatenated String and return a {@link Set} of all elements in the
* passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The {@link Set} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static Set getExplodedToSet (@Nonnull final String sSep, @Nullable final String sElements)
{
return getExploded (sSep, sElements, -1, new HashSet ());
}
/**
* Take a concatenated String and return an ordered {@link LinkedHashSet} of
* all elements in the passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The ordered {@link Set} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static Set getExplodedToOrderedSet (@Nonnull final String sSep, @Nullable final String sElements)
{
return getExploded (sSep, sElements, -1, new LinkedHashSet ());
}
/**
* Take a concatenated String and return a sorted {@link TreeSet} of all
* elements in the passed string, using specified separator string.
*
* @param sSep
* The separator to use. May not be null.
* @param sElements
* The concatenated String to convert. May be null or
* empty.
* @return The sorted {@link Set} represented by the passed string. Never
* null. If the passed input string is null
* or "" an empty list is returned.
*/
@Nonnull
@ReturnsMutableCopy
public static SortedSet getExplodedToSortedSet (@Nonnull final String sSep, @Nullable final String sElements)
{
return getExploded (sSep, sElements, -1, new TreeSet ());
}
/**
* Get the passed string element repeated for a certain number of times. Each
* string element is simply appended at the end of the string.
*
* @param cElement
* The character to get repeated.
* @param nRepeats
* The number of repetitions to retrieve. May not be < 0.
* @return A non-null string containing the string element for
* the given number of times.
*/
@Nonnull
public static String getRepeated (final char cElement, @Nonnegative final int nRepeats)
{
ValueEnforcer.isGE0 (nRepeats, "Repeats");
if (nRepeats == 0)
return "";
if (nRepeats == 1)
return Character.toString (cElement);
final char [] aElement = new char [nRepeats];
Arrays.fill (aElement, cElement);
return new String (aElement);
}
/**
* Get the passed string element repeated for a certain number of times. Each
* string element is simply appended at the end of the string.
*
* @param sElement
* The string to get repeated. May not be null.
* @param nRepeats
* The number of repetitions to retrieve. May not be < 0.
* @return A non-null string containing the string element for
* the given number of times.
*/
@Nonnull
public static String getRepeated (@Nonnull final String sElement, @Nonnegative final int nRepeats)
{
ValueEnforcer.notNull (sElement, "Element");
ValueEnforcer.isGE0 (nRepeats, "Repeats");
final int nElementLength = sElement.length ();
// Check if result length would exceed int range
if ((long) nElementLength * nRepeats > Integer.MAX_VALUE)
throw new IllegalArgumentException ("Resulting string exceeds the maximum integer length");
if (nElementLength == 0 || nRepeats == 0)
return "";
if (nRepeats == 1)
return sElement;
// use character version
if (nElementLength == 1)
return getRepeated (sElement.charAt (0), nRepeats);
// combine via StringBuilder
final StringBuilder ret = new StringBuilder (nElementLength * nRepeats);
for (int i = 0; i < nRepeats; ++i)
ret.append (sElement);
return ret.toString ();
}
/**
* Concatenate the strings sFront and sEnd. If either front or back is
* null or empty only the other element is returned. If both
* strings are null or empty and empty String is returned.
*
* @param sFront
* Front string. May be null.
* @param sEnd
* May be null.
* @return The concatenated string. Never null.
*/
@Nonnull
public static String getConcatenatedOnDemand (@Nullable final String sFront, @Nullable final String sEnd)
{
if (sFront == null)
return sEnd == null ? "" : sEnd;
if (sEnd == null)
return sFront;
return sFront + sEnd;
}
/**
* Concatenate the strings sFront and sEnd by the "sSep" string. If either
* front or back is null or empty, the separator is not applied.
*
* @param sFront
* Front string. May be null.
* @param sSep
* Separator string. May be null.
* @param sEnd
* May be null.
* @return The concatenated string.
*/
@Nonnull
public static String getConcatenatedOnDemand (@Nullable final String sFront,
@Nullable final String sSep,
@Nullable final String sEnd)
{
final StringBuilder aSB = new StringBuilder ();
if (hasText (sFront))
{
aSB.append (sFront);
if (hasText (sSep) && hasText (sEnd))
aSB.append (sSep);
}
if (hasText (sEnd))
aSB.append (sEnd);
return aSB.toString ();
}
/**
* Concatenate the strings sFront and sEnd by the "cSep" separator. If either
* front or back is null or empty, the separator is not applied.
*
* @param sFront
* Front string. May be null.
* @param cSep
* Separator character.
* @param sEnd
* May be null.
* @return The concatenated string.
*/
@Nonnull
public static String getConcatenatedOnDemand (@Nullable final String sFront,
final char cSep,
@Nullable final String sEnd)
{
final StringBuilder aSB = new StringBuilder ();
if (hasText (sFront))
{
aSB.append (sFront);
if (hasText (sEnd))
aSB.append (cSep);
}
if (hasText (sEnd))
aSB.append (sEnd);
return aSB.toString ();
}
public static boolean startsWith (@Nullable final CharSequence aCS, final char c)
{
return hasText (aCS) && aCS.charAt (0) == c;
}
public static boolean startsWithAny (@Nullable final CharSequence aCS, @Nullable final char [] aChars)
{
if (hasText (aCS) && aChars != null)
{
final char cFirst = aCS.charAt (0);
for (final char c : aChars)
if (cFirst == c)
return true;
}
return false;
}
public static boolean startsWithIgnoreCase (@Nullable final CharSequence aCS, final char c)
{
return hasText (aCS) && Character.toLowerCase (aCS.charAt (0)) == Character.toLowerCase (c);
}
public static boolean startsWith (@Nullable final CharSequence aCS, @Nullable final CharSequence aSearch)
{
if (aCS == null || aSearch == null)
return false;
final int nSearchLength = aSearch.length ();
return aCS.length () >= nSearchLength && aCS.subSequence (0, nSearchLength).equals (aSearch);
}
public static boolean startsWithIgnoreCase (@Nullable final String sStr, @Nullable final String sSearch)
{
if (sStr == null || sSearch == null)
return false;
final int nSearchLength = sSearch.length ();
return sStr.length () >= nSearchLength && sStr.substring (0, nSearchLength).equalsIgnoreCase (sSearch);
}
public static boolean endsWith (@Nullable final CharSequence aCS, final char c)
{
return hasText (aCS) && getLastChar (aCS) == c;
}
public static boolean endsWithAny (@Nullable final CharSequence aCS, @Nullable final char [] aChars)
{
if (hasText (aCS) && aChars != null)
{
final char cLast = getLastChar (aCS);
for (final char c : aChars)
if (cLast == c)
return true;
}
return false;
}
public static boolean endsWith (@Nullable final CharSequence aCS, @Nullable final CharSequence aSearch)
{
if (aCS == null || aSearch == null)
return false;
final int nCSLength = aCS.length ();
final int nSearchLength = aSearch.length ();
return nCSLength >= nSearchLength && aCS.subSequence (nCSLength - nSearchLength, nCSLength).equals (aSearch);
}
public static boolean endsWithIgnoreCase (@Nullable final CharSequence aCS, final char c)
{
return hasText (aCS) && Character.toLowerCase (getLastChar (aCS)) == Character.toLowerCase (c);
}
public static boolean endsWithIgnoreCase (@Nullable final String sStr, @Nullable final String sSearch)
{
if (sStr == null || sSearch == null)
return false;
final int nStrLength = sStr.length ();
final int nSearchLength = sSearch.length ();
return nStrLength >= nSearchLength &&
sStr.substring (nStrLength - nSearchLength, nStrLength).equalsIgnoreCase (sSearch);
}
/**
* Get the first index of sSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(String)
*/
public static int getIndexOf (@Nullable final String sText, @Nullable final String sSearch)
{
return sText != null && sSearch != null && sText.length () >= sSearch.length () ? sText.indexOf (sSearch)
: STRING_NOT_FOUND;
}
/**
* Get the first index of sSearch within sText starting at index nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param sSearch
* The text to search for. May be null.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(String,int)
*/
public static int getIndexOf (@Nullable final String sText,
@Nonnegative final int nFromIndex,
@Nullable final String sSearch)
{
return sText != null && sSearch != null && (sText.length () - nFromIndex) >= sSearch.length () ? sText.indexOf (sSearch,
nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the last index of sSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(String)
*/
public static int getLastIndexOf (@Nullable final String sText, @Nullable final String sSearch)
{
return sText != null && sSearch != null && sText.length () >= sSearch.length () ? sText.lastIndexOf (sSearch)
: STRING_NOT_FOUND;
}
/**
* Get the last index of sSearch within sText starting at index nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param sSearch
* The text to search for. May be null.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(String,int)
*/
public static int getLastIndexOf (@Nullable final String sText,
@Nonnegative final int nFromIndex,
@Nullable final String sSearch)
{
return sText != null && sSearch != null && (sText.length () - nFromIndex) >= sSearch.length () ? sText.lastIndexOf (sSearch,
nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the first index of cSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The character to search for. May be null.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if cSearch was not found or if any
* parameter was null.
* @see String#indexOf(int)
*/
public static int getIndexOf (@Nullable final String sText, final char cSearch)
{
return sText != null && sText.length () >= 1 ? sText.indexOf (cSearch) : STRING_NOT_FOUND;
}
/**
* Get the first index of cSearch within sText starting at index nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param cSearch
* The character to search for. May be null.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if cSearch was not found or if any
* parameter was null.
* @see String#indexOf(int,int)
*/
public static int getIndexOf (@Nullable final String sText, @Nonnegative final int nFromIndex, final char cSearch)
{
return sText != null && (sText.length () - nFromIndex) >= 1 ? sText.indexOf (cSearch, nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the last index of cSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The character to search for. May be null.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if cSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(int)
*/
public static int getLastIndexOf (@Nullable final String sText, final char cSearch)
{
return sText != null && sText.length () >= 1 ? sText.lastIndexOf (cSearch) : STRING_NOT_FOUND;
}
/**
* Get the last index of cSearch within sText starting at index nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param cSearch
* The character to search for. May be null.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if cSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(int,int)
*/
public static int getLastIndexOf (@Nullable final String sText, @Nonnegative final int nFromIndex, final char cSearch)
{
return sText != null && (sText.length () - nFromIndex) >= 1 ? sText.lastIndexOf (cSearch, nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the first index of sSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(String)
*/
public static int getIndexOfIgnoreCase (@Nullable final String sText,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sSearch != null && sText.length () >= sSearch.length () ? sText.toLowerCase (aSortLocale)
.indexOf (sSearch.toLowerCase (aSortLocale))
: STRING_NOT_FOUND;
}
/**
* Get the first index of sSearch within sText ignoring case starting at index
* nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(String)
*/
public static int getIndexOfIgnoreCase (@Nullable final String sText,
@Nonnegative final int nFromIndex,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sSearch != null && (sText.length () - nFromIndex) >= sSearch.length () ? sText.toLowerCase (aSortLocale)
.indexOf (sSearch.toLowerCase (aSortLocale),
nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the last index of sSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(String)
*/
public static int getLastIndexOfIgnoreCase (@Nullable final String sText,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sSearch != null && sText.length () >= sSearch.length () ? sText.toLowerCase (aSortLocale)
.lastIndexOf (sSearch.toLowerCase (aSortLocale))
: STRING_NOT_FOUND;
}
/**
* Get the last index of sSearch within sText ignoring case starting at index
* nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(String)
*/
public static int getLastIndexOfIgnoreCase (@Nullable final String sText,
@Nonnegative final int nFromIndex,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sSearch != null && (sText.length () - nFromIndex) >= sSearch.length () ? sText.toLowerCase (aSortLocale)
.lastIndexOf (sSearch.toLowerCase (aSortLocale),
nFromIndex)
: STRING_NOT_FOUND;
}
/**
* Get the first index of cSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The char to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(int)
*/
public static int getIndexOfIgnoreCase (@Nullable final String sText,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sText.length () >= 1 ? sText.toLowerCase (aSortLocale)
.indexOf (Character.toLowerCase (cSearch)) : STRING_NOT_FOUND;
}
/**
* Get the first index of cSearch within sText ignoring case starting at index
* nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param cSearch
* The char to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The first index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#indexOf(int)
*/
public static int getIndexOfIgnoreCase (@Nullable final String sText,
@Nonnegative final int nFromIndex,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && (sText.length () - nFromIndex) >= 1 ? sText.toLowerCase (aSortLocale)
.indexOf (Character.toLowerCase (cSearch),
nFromIndex) : STRING_NOT_FOUND;
}
/**
* Get the last index of cSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The char to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(int)
*/
public static int getLastIndexOfIgnoreCase (@Nullable final String sText,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sText.length () >= 1 ? sText.toLowerCase (aSortLocale)
.lastIndexOf (Character.toLowerCase (cSearch))
: STRING_NOT_FOUND;
}
/**
* Get the last index of cSearch within sText ignoring case starting at index
* nFromIndex.
*
* @param sText
* The text to search in. May be null.
* @param nFromIndex
* The index to start searching in the source string
* @param cSearch
* The char to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return The last index of sSearch within sText or
* {@value #STRING_NOT_FOUND} if sSearch was not found or if any
* parameter was null.
* @see String#lastIndexOf(int)
*/
public static int getLastIndexOfIgnoreCase (@Nullable final String sText,
@Nonnegative final int nFromIndex,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && (sText.length () - nFromIndex) >= 1 ? sText.toLowerCase (aSortLocale)
.lastIndexOf (Character.toLowerCase (cSearch),
nFromIndex) : STRING_NOT_FOUND;
}
/**
* Check if sSearch is contained within sText.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @return true if sSearch is contained in sText,
* false otherwise.
* @see String#contains(CharSequence)
*/
public static boolean contains (@Nullable final String sText, @Nullable final String sSearch)
{
return getIndexOf (sText, sSearch) != STRING_NOT_FOUND;
}
/**
* Check if cSearch is contained within sText.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The character to search for. May be null.
* @return true if cSearch is contained in sText,
* false otherwise.
* @see String#contains(CharSequence)
*/
public static boolean contains (@Nullable final String sText, final char cSearch)
{
return getIndexOf (sText, cSearch) != STRING_NOT_FOUND;
}
/**
* Check if sSearch is contained within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return true if sSearch is contained in sText,
* false otherwise.
* @see String#contains(CharSequence)
*/
public static boolean containsIgnoreCase (@Nullable final String sText,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return getIndexOfIgnoreCase (sText, sSearch, aSortLocale) != STRING_NOT_FOUND;
}
/**
* Check if cSearch is contained within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The char to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return true if sSearch is contained in sText,
* false otherwise.
* @see String#indexOf(int)
*/
public static boolean containsIgnoreCase (@Nullable final String sText,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return getIndexOfIgnoreCase (sText, cSearch, aSortLocale) != STRING_NOT_FOUND;
}
/**
* Check if any of the passed searched characters is contained in the input
* char array.
*
* @param aInput
* The input char array. May be null.
* @param aSearchChars
* The char array to search. May not be null.
* @return true if at least any of the search char is contained
* in the input char array, false otherwise.
*/
public static boolean containsAny (@Nullable final char [] aInput, @Nonnull final char [] aSearchChars)
{
ValueEnforcer.notNull (aSearchChars, "SearchChars");
if (aInput != null)
for (final char cIn : aInput)
if (ArrayHelper.contains (aSearchChars, cIn))
return true;
return false;
}
/**
* Check if any of the passed searched characters in contained in the input
* string.
*
* @param sInput
* The input string. May be null.
* @param aSearchChars
* The char array to search. May not be null.
* @return true if at least any of the search char is contained
* in the input char array, false otherwise.
*/
public static boolean containsAny (@Nullable final String sInput, @Nonnull final char [] aSearchChars)
{
return sInput != null && containsAny (sInput.toCharArray (), aSearchChars);
}
/**
* Count the number of occurrences of sSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @return A non-negative number of occurrences.
*/
@Nonnegative
public static int getOccurrenceCount (@Nullable final String sText, @Nullable final String sSearch)
{
int ret = 0;
final int nTextLength = getLength (sText);
final int nSearchLength = getLength (sSearch);
if (nSearchLength > 0 && nTextLength >= nSearchLength)
{
int nLastIndex = 0, nIndex;
do
{
// Start searching from the last result
nIndex = getIndexOf (sText, nLastIndex, sSearch);
if (nIndex != STRING_NOT_FOUND)
{
// Match found
++ret;
// Identify the next starting position (relative index + number of
// search strings)
nLastIndex = nIndex + nSearchLength;
}
} while (nIndex != STRING_NOT_FOUND);
}
return ret;
}
/**
* Count the number of occurrences of sSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param sSearch
* The text to search for. May be null.
* @param aSortLocale
* The locale to be used for case unifying.
* @return A non-negative number of occurrences.
*/
@Nonnegative
public static int getOccurrenceCountIgnoreCase (@Nullable final String sText,
@Nullable final String sSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null && sSearch != null ? getOccurrenceCount (sText.toLowerCase (aSortLocale),
sSearch.toLowerCase (aSortLocale)) : 0;
}
/**
* Count the number of occurrences of cSearch within sText.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The character to search for.
* @return A non-negative number of occurrences.
*/
@Nonnegative
public static int getOccurrenceCount (@Nullable final String sText, final char cSearch)
{
int ret = 0;
final int nTextLength = getLength (sText);
if (nTextLength >= 1)
{
int nLastIndex = 0, nIndex;
do
{
// Start searching from the last result
nIndex = getIndexOf (sText, nLastIndex, cSearch);
if (nIndex != STRING_NOT_FOUND)
{
// Match found
++ret;
// Identify the next starting position (relative index + number of
// search strings)
nLastIndex = nIndex + 1;
}
} while (nIndex != STRING_NOT_FOUND);
}
return ret;
}
/**
* Count the number of occurrences of cSearch within sText ignoring case.
*
* @param sText
* The text to search in. May be null.
* @param cSearch
* The character to search for.
* @param aSortLocale
* The locale to be used for case unifying.
* @return A non-negative number of occurrences.
*/
@Nonnegative
public static int getOccurrenceCountIgnoreCase (@Nullable final String sText,
final char cSearch,
@Nonnull final Locale aSortLocale)
{
return sText != null ? getOccurrenceCount (sText.toLowerCase (aSortLocale), Character.toLowerCase (cSearch)) : 0;
}
/**
* Remove any leading whitespaces from the passed string.
*
* @param s
* the String to be trimmed
* @return the original String with all leading whitespaces removed
*/
@Nullable
@CheckReturnValue
public static String trimLeadingWhitespaces (@Nullable final String s)
{
final int n = getLeadingWhitespaceCount (s);
return n == 0 ? s : s.substring (n, s.length ());
}
/**
* Remove any trailing whitespaces from the passed string.
*
* @param s
* the String to be cut
* @return the original String with all trailing whitespaces removed
*/
@Nullable
@CheckReturnValue
public static String trimTrailingWhitespaces (@Nullable final String s)
{
final int n = getTrailingWhitespaceCount (s);
return n == 0 ? s : s.substring (0, s.length () - n);
}
/**
* Trim the passed lead from the source value. If the source value does not
* start with the passed lead, nothing happens.
*
* @param sSrc
* The input source string
* @param sLead
* The string to be trimmed of the beginning
* @return The trimmed string, or the original input string, if the lead was
* not found
* @see #trimEnd(String, String)
* @see #trimStartAndEnd(String, String)
* @see #trimStartAndEnd(String, String, String)
*/
@Nullable
@CheckReturnValue
public static String trimStart (@Nullable final String sSrc, @Nullable final String sLead)
{
return startsWith (sSrc, sLead) ? sSrc.substring (sLead.length (), sSrc.length ()) : sSrc;
}
/**
* Trim the passed tail from the source value. If the source value does not
* end with the passed tail, nothing happens.
*
* @param sSrc
* The input source string
* @param sTail
* The string to be trimmed of the end
* @return The trimmed string, or the original input string, if the tail was
* not found
* @see #trimStart(String, String)
* @see #trimStartAndEnd(String, String)
* @see #trimStartAndEnd(String, String, String)
*/
@Nullable
@CheckReturnValue
public static String trimEnd (@Nullable final String sSrc, @Nullable final String sTail)
{
return endsWith (sSrc, sTail) ? sSrc.substring (0, sSrc.length () - sTail.length ()) : sSrc;
}
/**
* Trim the passed lead and tail from the source value. If the source value
* does not start with the passed trimmed value, nothing happens.
*
* @param sSrc
* The input source string
* @param sValueToTrim
* The string to be trimmed of the beginning and the end
* @return The trimmed string, or the original input string, if the value to
* trim was not found
* @see #trimStart(String, String)
* @see #trimEnd(String, String)
* @see #trimStartAndEnd(String, String, String)
*/
@Nullable
@CheckReturnValue
public static String trimStartAndEnd (@Nullable final String sSrc, @Nullable final String sValueToTrim)
{
return trimStartAndEnd (sSrc, sValueToTrim, sValueToTrim);
}
/**
* Trim the passed lead and tail from the source value. If the source value
* does not start with the passed lead and does not end with the passed tail,
* nothing happens.
*
* @param sSrc
* The input source string
* @param sLead
* The string to be trimmed of the beginning
* @param sTail
* The string to be trimmed of the end
* @return The trimmed string, or the original input string, if the lead and
* the tail were not found
* @see #trimStart(String, String)
* @see #trimEnd(String, String)
* @see #trimStartAndEnd(String, String)
*/
@Nullable
@CheckReturnValue
public static String trimStartAndEnd (@Nullable final String sSrc,
@Nullable final String sLead,
@Nullable final String sTail)
{
final String sInbetween = trimStart (sSrc, sLead);
return trimEnd (sInbetween, sTail);
}
/**
* Trim the passed string, if it is not null.
*
* @param s
* The string to be trimmed. May be null.
* @return null if the input string was null, the
* non-null trimmed string otherwise.
* @see String#trim()
*/
@Nullable
@CheckReturnValue
public static String trim (@Nullable final String s)
{
return hasNoText (s) ? s : s.trim ();
}
/**
* Get the first character of the passed character sequence
*
* @param aCS
* The source character sequence
* @return {@link CGlobal#ILLEGAL_CHAR} if the passed sequence was empty
*/
public static char getFirstChar (@Nullable final CharSequence aCS)
{
return hasText (aCS) ? aCS.charAt (0) : CGlobal.ILLEGAL_CHAR;
}
/**
* Get the first character of the passed array
*
* @param aChars
* The character array
* @return {@link CGlobal#ILLEGAL_CHAR} if the passed array was empty
*/
public static char getFirstChar (@Nullable final char [] aChars)
{
return ArrayHelper.getFirst (aChars, CGlobal.ILLEGAL_CHAR);
}
/**
* Get the last character of the passed character sequence
*
* @param aCS
* The source character sequence
* @return {@link CGlobal#ILLEGAL_CHAR} if the passed sequence was empty
*/
public static char getLastChar (@Nullable final CharSequence aCS)
{
final int nLength = getLength (aCS);
return nLength > 0 ? aCS.charAt (nLength - 1) : CGlobal.ILLEGAL_CHAR;
}
/**
* Get the last character of the passed array
*
* @param aChars
* The character array
* @return {@link CGlobal#ILLEGAL_CHAR} if the passed array was empty
*/
public static char getLastChar (@Nullable final char [] aChars)
{
return ArrayHelper.getLast (aChars, CGlobal.ILLEGAL_CHAR);
}
@Nonnegative
public static int getCharCount (@Nullable final String s, final char cSearch)
{
return s == null ? 0 : getCharCount (s.toCharArray (), cSearch);
}
@Nonnegative
public static int getCharCount (@Nullable final char [] aChars, final char cSearch)
{
int ret = 0;
if (aChars != null)
for (final char c : aChars)
if (c == cSearch)
++ret;
return ret;
}
@Nonnegative
public static int getLineCount (@Nullable final String s)
{
return getLineCount (s, '\n');
}
@Nonnegative
public static int getLineCount (@Nullable final String s, final char cLineSep)
{
return 1 + getCharCount (s, cLineSep);
}
/**
* Get the number of characters the passed value would occupy in a string
* representation.
* Copied from java.lang.Integer#StringSize
*
* @param nValue
* The integer value to check. May be be positive or negative.
* @return Number of characters required. Alyways > 0.
*/
@Nonnegative
public static int getCharacterCount (final int nValue)
{
// index is always one character less than the real size; that's why nPrefix
// is 1 more!
final int nPrefix = nValue < 0 ? 2 : 1;
final int nRealValue = MathHelper.abs (nValue);
for (int nIndex = 0;; nIndex++)
if (nRealValue <= s_aSizeTableInt[nIndex])
return nPrefix + nIndex;
}
/**
* Get the number of characters the passed value would occupy in a string
* representation.
*
* @param nValue
* The long value to check. May be be positive or negative.
* @return Number of characters required. Always > 0.
*/
@Nonnegative
public static int getCharacterCount (final long nValue)
{
// index is always one character less than the real size; that's why nPrefix
// is 1 more!
final int nPrefix = nValue < 0 ? 2 : 1;
final long nRealValue = MathHelper.abs (nValue);
for (int nIndex = 0;; nIndex++)
if (nRealValue <= s_aSizeTableLong[nIndex])
return nPrefix + nIndex;
}
@Nonnull
public static String getCutAfterLength (@Nonnull final String sValue, @Nonnegative final int nMaxLength)
{
return getCutAfterLength (sValue, nMaxLength, null);
}
@Nonnull
public static String getCutAfterLength (@Nonnull final String sValue,
@Nonnegative final int nMaxLength,
@Nullable final String sNewSuffix)
{
ValueEnforcer.notNull (sValue, "Value");
ValueEnforcer.isGE0 (nMaxLength, "MaxLength");
if (sValue.length () <= nMaxLength)
return sValue;
if (isEmpty (sNewSuffix))
return sValue.substring (0, nMaxLength);
return sValue.substring (0, nMaxLength) + sNewSuffix;
}
/**
* Same as {@link #replaceAll(String, String, CharSequence)} but allowing for
* a null new-value, which is than interpreted as an empty string
* instead.
*
* @param sInputString
* The input string where the text should be replace. If this parameter
* is null or empty, no replacement is done.
* @param sSearchText
* The string to be replaced. May neither be null nor
* empty.
* @param aReplacementText
* The string with the replacement. May be null or empty.
* @return The input string as is, if the input string is empty or if the
* string to be replaced is not contained.
*/
public static String replaceAllSafe (@Nullable final String sInputString,
@Nonnull final String sSearchText,
@Nullable final CharSequence aReplacementText)
{
return replaceAll (sInputString, sSearchText, getNotNull (aReplacementText, ""));
}
/**
* This is a fast replacement for
* {@link String#replace(CharSequence, CharSequence)}. The problem with the
* mentioned {@link String} method is, that is uses internally regular
* expressions which use a synchronized block to compile the patterns. This
* method is inherently thread safe since {@link String} is immutable and
* we're operating on different temporary {@link StringBuilder} objects.
*
* @param sInputString
* The input string where the text should be replace. If this parameter
* is null or empty, no replacement is done.
* @param sSearchText
* The string to be replaced. May neither be null nor
* empty.
* @param aReplacementText
* The string with the replacement. May not be null but
* may be empty.
* @return The input string as is, if the input string is empty or if the
* search pattern and the replacement are equal or if the string to be
* replaced is not contained.
*/
@Nullable
public static String replaceAll (@Nullable final String sInputString,
@Nonnull final String sSearchText,
@Nonnull final CharSequence aReplacementText)
{
ValueEnforcer.notEmpty (sSearchText, "SearchText");
ValueEnforcer.notNull (aReplacementText, "ReplacementText");
// Is input string empty?
if (hasNoText (sInputString))
return sInputString;
// Replace old with the same new?
final int nOldLength = sSearchText.length ();
final int nNewLength = aReplacementText.length ();
if (nOldLength == nNewLength)
{
// Any change?
if (sSearchText.equals (aReplacementText))
return sInputString;
if (nOldLength == 1)
{
// Use char version which is more efficient
return replaceAll (sInputString, sSearchText.charAt (0), aReplacementText.charAt (0));
}
}
// Does the old text occur anywhere?
int nIndex = sInputString.indexOf (sSearchText, 0);
if (nIndex == STRING_NOT_FOUND)
return sInputString;
// build output buffer
final StringBuilder ret = new StringBuilder (nOldLength >= nNewLength ? sInputString.length ()
: sInputString.length () * 2);
int nOldIndex = 0;
do
{
ret.append (sInputString, nOldIndex, nIndex).append (aReplacementText);
nIndex += nOldLength;
nOldIndex = nIndex;
nIndex = sInputString.indexOf (sSearchText, nIndex);
} while (nIndex != STRING_NOT_FOUND);
ret.append (sInputString, nOldIndex, sInputString.length ());
return ret.toString ();
}
/**
* This is a fast replacement for
* {@link String#replace(CharSequence, CharSequence)} for characters. The
* problem with the mentioned String method is, that is uses internally
* regular expressions which use a synchronized block to compile the patterns.
* This method is inherently thread safe since {@link String} is immutable and
* we're operating on different temporary {@link StringBuilder} objects.
*
* @param sInputString
* The input string where the text should be replace. If this parameter
* is null or empty, no replacement is done.
* @param cSearchChar
* The character to be replaced.
* @param cReplacementChar
* The character with the replacement.
* @return The input string as is, if the input string is empty or if the
* search pattern and the replacement are equal or if the string to be
* replaced is not contained.
*/
@Nullable
public static String replaceAll (@Nullable final String sInputString,
final char cSearchChar,
final char cReplacementChar)
{
// Is input string empty?
if (hasNoText (sInputString))
return sInputString;
// Replace old with the same new?
if (cSearchChar == cReplacementChar)
return sInputString;
// Does the old text occur anywhere?
int nIndex = sInputString.indexOf (cSearchChar, 0);
if (nIndex == STRING_NOT_FOUND)
return sInputString;
// build output buffer
final StringBuilder ret = new StringBuilder (sInputString.length ());
int nOldIndex = 0;
do
{
ret.append (sInputString, nOldIndex, nIndex).append (cReplacementChar);
nIndex++;
nOldIndex = nIndex;
nIndex = sInputString.indexOf (cSearchChar, nIndex);
} while (nIndex != STRING_NOT_FOUND);
ret.append (sInputString, nOldIndex, sInputString.length ());
return ret.toString ();
}
/**
* Just calls replaceAll as long as there are still replacements
* found
*
* @param sInputString
* The input string where the text should be replace. If this parameter
* is null or empty, no replacement is done.
* @param sSearchText
* The string to be replaced. May neither be null nor
* empty.
* @param sReplacementText
* The string with the replacement. May not be null but
* may be empty.
* @return The input string as is, if the input string is empty or if the
* string to be replaced is not contained.
*/
@Nullable
public static String replaceAllRepeatedly (@Nullable final String sInputString,
@Nonnull final String sSearchText,
@Nonnull final String sReplacementText)
{
ValueEnforcer.notEmpty (sSearchText, "SearchText");
ValueEnforcer.notNull (sReplacementText, "ReplacementText");
if (sReplacementText.contains (sSearchText))
throw new IllegalArgumentException ("Loop detection: replacementText must not contain searchText");
// Is input string empty?
if (hasNoText (sInputString))
return sInputString;
String sRet = sInputString;
String sLastLiteral;
do
{
sLastLiteral = sRet;
sRet = replaceAll (sRet, sSearchText, sReplacementText);
} while (!sLastLiteral.equals (sRet));
return sRet;
}
/**
* Get the result length (in characters) when replacing all patterns with the
* replacements on the passed input array.
*
* @param aInputString
* Input char array. May not be null.
* @param aSearchChars
* The one-character search patterns. May not be null.
* @param aReplacementStrings
* The replacements to be performed. May not be null. The
* first dimension of this array must have exactly the same amount of
* elements as the patterns parameter array.
* @return {@link CGlobal#ILLEGAL_UINT} if no replacement was needed, and
* therefore the length of the input array could be used.
*/
public static int getReplaceMultipleResultLength (@Nonnull final char [] aInputString,
@Nonnull @Nonempty final char [] aSearchChars,
@Nonnull @Nonempty final char [][] aReplacementStrings)
{
int nResultLen = 0;
boolean bAnyReplacement = false;
for (final char cInput : aInputString)
{
// In case no replacement is found use a single char
int nReplacementLength = 1;
for (int nIndex = 0; nIndex < aSearchChars.length; nIndex++)
if (cInput == aSearchChars[nIndex])
{
nReplacementLength = aReplacementStrings[nIndex].length;
bAnyReplacement = true;
break;
}
nResultLen += nReplacementLength;
}
return bAnyReplacement ? nResultLen : CGlobal.ILLEGAL_UINT;
}
/**
* Optimized replace method that replaces a set of characters with a set of
* strings. This method was created for efficient XML special character
* replacements!
*
* @param sInputString
* The input string.
* @param aSearchChars
* The characters to replace.
* @param aReplacementStrings
* The new strings to be inserted instead. Must have the same array
* length as aPatterns.
* @return The replaced version of the string or an empty char array if the
* input string was null.
*/
@Nonnull
public static char [] replaceMultiple (@Nullable final String sInputString,
@Nonnull final char [] aSearchChars,
@Nonnull final char [][] aReplacementStrings)
{
// Any input text?
if (hasNoText (sInputString))
return ArrayHelper.EMPTY_CHAR_ARRAY;
return replaceMultiple (sInputString.toCharArray (), aSearchChars, aReplacementStrings);
}
/**
* Optimized replace method that replaces a set of characters with a set of
* strings. This method was created for efficient XML special character
* replacements!
*
* @param aInput
* The input string.
* @param aSearchChars
* The characters to replace.
* @param aReplacementStrings
* The new strings to be inserted instead. Must have the same array
* length as aPatterns.
* @return The replaced version of the string or an empty char array if the
* input string was null.
*/
@Nonnull
public static char [] replaceMultiple (@Nullable final char [] aInput,
@Nonnull final char [] aSearchChars,
@Nonnull final char [][] aReplacementStrings)
{
ValueEnforcer.notNull (aSearchChars, "SearchChars");
ValueEnforcer.notNull (aReplacementStrings, "ReplacementStrings");
if (aSearchChars.length != aReplacementStrings.length)
throw new IllegalArgumentException ("array length mismatch");
// Any input text?
if (aInput == null || aInput.length == 0)
return ArrayHelper.EMPTY_CHAR_ARRAY;
// Any replacement patterns?
if (aSearchChars.length == 0)
return aInput;
// get result length
final int nResultLen = getReplaceMultipleResultLength (aInput, aSearchChars, aReplacementStrings);
// nothing to replace in here?
if (nResultLen == CGlobal.ILLEGAL_UINT)
return aInput;
// build result
final char [] aOutput = new char [nResultLen];
int nOutputIndex = 0;
// For all input chars
for (final char cInput : aInput)
{
boolean bFoundReplacement = false;
for (int nPatternIndex = 0; nPatternIndex < aSearchChars.length; nPatternIndex++)
{
if (cInput == aSearchChars[nPatternIndex])
{
final char [] aReplacement = aReplacementStrings[nPatternIndex];
final int nReplacementLength = aReplacement.length;
System.arraycopy (aReplacement, 0, aOutput, nOutputIndex, nReplacementLength);
nOutputIndex += nReplacementLength;
bFoundReplacement = true;
break;
}
}
if (!bFoundReplacement)
{
// copy char as is
aOutput[nOutputIndex++] = cInput;
}
}
return aOutput;
}
/**
* Specialized version of {@link #replaceMultiple(String, char[], char[][])}
* where the object where the output should be appended is passed in as a
* parameter. This has the advantage, that not length calculation needs to
* take place!
*
* @param sInputString
* The input string.
* @param aSearchChars
* The characters to replace.
* @param aReplacementStrings
* The new strings to be inserted instead. Must have the same array
* length as aPatterns.
* @param aTarget
* Where the replaced objects should be written to. May not be
* null.
* @return The number of replacements performed. Always ≥ 0.
* @throws IOException
* In case writing to the Writer fails
*/
@Nonnegative
public static int replaceMultipleTo (@Nullable final String sInputString,
@Nonnull final char [] aSearchChars,
@Nonnull final char [][] aReplacementStrings,
@Nonnull final Writer aTarget) throws IOException
{
if (hasNoText (sInputString))
return 0;
return replaceMultipleTo (sInputString.toCharArray (), aSearchChars, aReplacementStrings, aTarget);
}
/**
* Specialized version of {@link #replaceMultiple(String, char[], char[][])}
* where the object where the output should be appended is passed in as a
* parameter. This has the advantage, that not length calculation needs to
* take place!
*
* @param aInput
* The input string.
* @param aSearchChars
* The characters to replace.
* @param aReplacementStrings
* The new strings to be inserted instead. Must have the same array
* length as aPatterns.
* @param aTarget
* Where the replaced objects should be written to. May not be
* null.
* @return The number of replacements performed. Always ≥ 0.
* @throws IOException
* In case writing to the Writer fails
*/
@Nonnegative
public static int replaceMultipleTo (@Nullable final char [] aInput,
@Nonnull final char [] aSearchChars,
@Nonnull final char [][] aReplacementStrings,
@Nonnull final Writer aTarget) throws IOException
{
ValueEnforcer.notNull (aSearchChars, "SearchChars");
ValueEnforcer.notNull (aReplacementStrings, "ReplacementStrings");
if (aSearchChars.length != aReplacementStrings.length)
throw new IllegalArgumentException ("array length mismatch");
ValueEnforcer.notNull (aTarget, "Target");
if (aInput == null || aInput.length == 0)
return 0;
if (aSearchChars.length == 0)
{
// No modifications required
aTarget.write (aInput);
return 0;
}
// for all input string characters
int nFirstNonReplace = 0;
int nInputIndex = 0;
int nTotalReplacements = 0;
final int nMaxSearchChars = aSearchChars.length;
for (final char cInput : aInput)
{
for (int nPatternIndex = 0; nPatternIndex < nMaxSearchChars; nPatternIndex++)
{
if (cInput == aSearchChars[nPatternIndex])
{
if (nFirstNonReplace < nInputIndex)
aTarget.write (aInput, nFirstNonReplace, nInputIndex - nFirstNonReplace);
nFirstNonReplace = nInputIndex + 1;
aTarget.write (aReplacementStrings[nPatternIndex]);
++nTotalReplacements;
break;
}
}
nInputIndex++;
}
if (nFirstNonReplace < nInputIndex)
aTarget.write (aInput, nFirstNonReplace, nInputIndex - nFirstNonReplace);
return nTotalReplacements;
}
/**
* Optimized replace method that replaces a set of characters with another
* character. This method was created for efficient unsafe character
* replacements!
*
* @param sInputString
* The input string.
* @param aSearchChars
* The characters to replace.
* @param cReplacementChar
* The new char to be used instead of the search chars.
* @return The replaced version of the string or an empty char array if the
* input string was null.
*/
@Nonnull
public static char [] replaceMultiple (@Nullable final String sInputString,
@Nonnull final char [] aSearchChars,
final char cReplacementChar)
{
ValueEnforcer.notNull (aSearchChars, "SearchChars");
// Any input text?
if (hasNoText (sInputString))
return ArrayHelper.EMPTY_CHAR_ARRAY;
// Get char array
final char [] aInput = sInputString.toCharArray ();
// Any replacement patterns?
if (aSearchChars.length == 0)
return aInput;
// build result
final char [] aOutput = new char [aInput.length];
int nOutputIndex = 0;
for (final char c : aInput)
{
if (ArrayHelper.contains (aSearchChars, c))
aOutput[nOutputIndex] = cReplacementChar;
else
aOutput[nOutputIndex] = c;
nOutputIndex++;
}
return aOutput;
}
/**
* Perform all string replacements on the input string as defined by the
* passed map. All replacements are done using
* {@link #replaceAll(String,String,CharSequence)} which is ok.
*
* @param sInputString
* The input string where the text should be replaced. May be
* null.
* @param aTransTable
* The map with the replacements to execute. If null is
* passed, the input string is not altered.
* @return null if the input string was null.
*/
@Nullable
public static String replaceMultiple (@Nullable final String sInputString,
@Nullable final Map aTransTable)
{
if (hasNoText (sInputString) || aTransTable == null || aTransTable.isEmpty ())
return sInputString;
String sOutput = sInputString;
for (final Entry aEntry : aTransTable.entrySet ())
sOutput = replaceAll (sOutput, aEntry.getKey (), aEntry.getValue ());
return sOutput;
}
/**
* Perform all string replacements on the input string as defined by the
* passed map. All replacements are done using
* {@link #replaceAll(String,String,CharSequence)} which is ok.
*
* @param sInputString
* The input string where the text should be replaced. May be
* null.
* @param aSearchTexts
* The texts to be searched. If null is passed, the input
* string is not altered.
* @param aReplacementTexts
* The texts to be used as the replacements. This array must have
* exactly the same number of elements than the searched texts! If
* null is passed, the input string is not altered.
* @return null if the input string was null. The
* unmodified input string if no search/replace patterns where
* provided.
*/
@SuppressWarnings ("null")
@Nullable
public static String replaceMultiple (@Nullable final String sInputString,
@Nullable final String [] aSearchTexts,
@Nullable final String [] aReplacementTexts)
{
if (hasNoText (sInputString))
return sInputString;
final int nSearchTextLength = aSearchTexts == null ? 0 : aSearchTexts.length;
final int nReplacementTextLength = aReplacementTexts == null ? 0 : aReplacementTexts.length;
if (nSearchTextLength != nReplacementTextLength)
throw new IllegalArgumentException ("Array length mismatch!");
// Nothing to replace?
if (nSearchTextLength == 0)
return sInputString;
String sOutput = sInputString;
for (int nIndex = 0; nIndex < nSearchTextLength; ++nIndex)
sOutput = replaceAll (sOutput, aSearchTexts[nIndex], aReplacementTexts[nIndex]);
return sOutput;
}
/**
* Remove all occurrences of the passed character from the specified input
* string
*
* @param sInputString
* The input string where the character should be removed. If this
* parameter is null or empty, no removing is done.
* @param cRemoveChar
* The character to be removed.
* @return The input string as is, if the input string is empty or if the
* remove char is not contained.
*/
@Nullable
public static String removeAll (@Nullable final String sInputString, final char cRemoveChar)
{
// Is input string empty?
if (hasNoText (sInputString))
return sInputString;
// Does the char occur anywhere?
final int nFirstIndex = sInputString.indexOf (cRemoveChar, 0);
if (nFirstIndex == STRING_NOT_FOUND)
return sInputString;
// build output buffer
final char [] aChars = sInputString.toCharArray ();
final int nMax = aChars.length;
final StringBuilder aSB = new StringBuilder (nMax);
// Copy the first chars where we know it is not contained
aSB.append (aChars, 0, nFirstIndex);
// Start searching after the first occurrence because we know that this is a
// char to be removed
for (int i = nFirstIndex; i < nMax; ++i)
{
final char c = aChars[i];
if (c != cRemoveChar)
aSB.append (c);
}
return aSB.toString ();
}
/**
* Get the length of the passed character sequence.
*
* @param aCS
* The character sequence who's length is to be determined. May be
* null.
* @return 0 if the parameter is null, its length otherwise.
* @see CharSequence#length()
*/
@Nonnegative
public static int getLength (@Nullable final CharSequence aCS)
{
return aCS == null ? 0 : aCS.length ();
}
/**
* Get the passed string but never return null. If the passed
* parameter is null an empty string is returned.
*
* @param s
* The parameter to be not null.
* @return An empty string if the passed parameter is null, the
* passed string otherwise.
*/
@Nonnull
public static String getNotNull (@Nullable final String s)
{
return getNotNull (s, "");
}
/**
* Get the passed string but never return null. If the passed
* parameter is null the second parameter is returned.
*
* @param s
* The parameter to be not null.
* @param sDefaultIfNull
* The value to be used of the first parameter is null.
* May be null but in this case the call to this method is
* obsolete.
* @return The passed default value if the string is null,
* otherwise the input string.
*/
@Nullable
public static String getNotNull (@Nullable final String s, final String sDefaultIfNull)
{
return s == null ? sDefaultIfNull : s;
}
/**
* Get the passed {@link CharSequence} but never return null. If
* the passed parameter is null an empty string is returned.
*
* @param s
* The parameter to be not null.
* @return An empty string if the passed parameter is null, the
* passed {@link CharSequence} otherwise.
*/
@Nonnull
public static CharSequence getNotNull (@Nullable final CharSequence s)
{
return getNotNull (s, "");
}
/**
* Get the passed {@link CharSequence} but never return null. If
* the passed parameter is null the second parameter is returned.
*
* @param s
* The parameter to be not null.
* @param sDefaultIfNull
* The value to be used of the first parameter is null.
* May be null but in this case the call to this method is
* obsolete.
* @return The passed default value if the string is null,
* otherwise the input {@link CharSequence}.
*/
@Nullable
public static CharSequence getNotNull (@Nullable final CharSequence s, final CharSequence sDefaultIfNull)
{
return s == null ? sDefaultIfNull : s;
}
/**
* Convert the passed object to a string using the {@link Object#toString()}
* method.
*
* @param aObject
* The value to be converted. May be null.
* @return An empty string in case the passed object was null.
* Never null.
* @see Object#toString()
*/
@Nonnull
public static String getToString (@Nullable final Object aObject)
{
return getToString (aObject, "");
}
/**
* Convert the passed object to a string using the {@link Object#toString()}
* method or otherwise return the passed default value.
*
* @param aObject
* The value to be converted. May be null.
* @param sNullValue
* The value to be returned in case the passed object is
* null. May be null itself.
* @return The passed default value in case the passed object was
* null or the result of {@link Object#toString()} on the
* passed object.
* @see Object#toString()
*/
@Nullable
public static String getToString (@Nullable final Object aObject, @Nullable final String sNullValue)
{
return aObject == null ? sNullValue : aObject.toString ();
}
/**
* Get the passed string without the first char.
*
* @param sStr
* The source string. May be null.
* @return An empty, non-null string if the passed string has a
* length ≤ 1.
*/
@Nonnull
public static String getWithoutLeadingChar (@Nullable final String sStr)
{
return getWithoutLeadingChars (sStr, 1);
}
/**
* Get the passed string without the specified number of leading chars.
*
* @param sStr
* The source string. May be null.
* @param nCount
* The number of chars to remove.
* @return An empty, non-null string if the passed string has a
* length ≤ nCount.
*/
@Nonnull
public static String getWithoutLeadingChars (@Nullable final String sStr, @Nonnegative final int nCount)
{
ValueEnforcer.isGE0 (nCount, "Count");
if (nCount == 0)
return sStr;
return getLength (sStr) <= nCount ? "" : sStr.substring (nCount);
}
/**
* Get the passed string without the last char.
*
* @param sStr
* The source string. May be null.
* @return An empty, non-null string if the passed string has a
* length ≤ 1.
*/
@Nonnull
public static String getWithoutTrailingChar (@Nullable final String sStr)
{
return getWithoutTrailingChars (sStr, 1);
}
/**
* Get the passed string without the specified number of trailing chars.
*
* @param sStr
* The source string. May be null.
* @param nCount
* The number of chars to remove.
* @return An empty, non-null string if the passed string has a
* length ≤ nCount.
*/
@Nonnull
public static String getWithoutTrailingChars (@Nullable final String sStr, @Nonnegative final int nCount)
{
ValueEnforcer.isGE0 (nCount, "Count");
if (nCount == 0)
return sStr;
final int nLength = getLength (sStr);
return nLength <= nCount ? "" : sStr.substring (0, nLength - nCount);
}
/**
* Get the passed string where all spaces (white spaces or unicode spaces)
* have been removed.
*
* @param sStr
* The source string. May be null
* @return A non-null string representing the passed string
* without any spaces
*/
@Nonnull
public static String getWithoutAnySpaces (@Nullable final String sStr)
{
if (sStr == null)
return "";
// Trim first
final char [] aChars = sStr.trim ().toCharArray ();
final StringBuilder aResult = new StringBuilder (aChars.length);
for (final char c : aChars)
if (!Character.isWhitespace (c) && !Character.isSpaceChar (c))
aResult.append (c);
return aResult.toString ();
}
@Nullable
private static String _getUntilFirst (@Nullable final String sStr,
final char cSearch,
final boolean bIncludingSearchChar)
{
final int nIndex = getIndexOf (sStr, cSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (0, nIndex + (bIncludingSearchChar ? 1 : 0));
}
/**
* Get everything from the string up to and including the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getUntilFirstIncl (@Nullable final String sStr, final char cSearch)
{
return _getUntilFirst (sStr, cSearch, true);
}
/**
* Get everything from the string up to and excluding first the passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getUntilFirstExcl (@Nullable final String sStr, final char cSearch)
{
return _getUntilFirst (sStr, cSearch, false);
}
@Nullable
private static String _getUntilFirst (@Nullable final String sStr,
@Nullable final String sSearch,
final boolean bIncludingSearchChar)
{
if (hasNoText (sSearch))
return "";
final int nIndex = getIndexOf (sStr, sSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (0, nIndex +
(bIncludingSearchChar ? sSearch.length () : 0));
}
/**
* Get everything from the string up to and including the first passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the empty string is
* returned.
*/
@Nullable
public static String getUntilFirstIncl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getUntilFirst (sStr, sSearch, true);
}
/**
* Get everything from the string up to and excluding the first passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the empty string is
* returned.
*/
@Nullable
public static String getUntilFirstExcl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getUntilFirst (sStr, sSearch, false);
}
@Nullable
private static String _getUntilLast (@Nullable final String sStr,
final char cSearch,
final boolean bIncludingSearchChar)
{
final int nIndex = getLastIndexOf (sStr, cSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (0, nIndex + (bIncludingSearchChar ? 1 : 0));
}
/**
* Get everything from the string up to and including the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getUntilLastIncl (@Nullable final String sStr, final char cSearch)
{
return _getUntilLast (sStr, cSearch, true);
}
/**
* Get everything from the string up to and excluding first the passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getUntilLastExcl (@Nullable final String sStr, final char cSearch)
{
return _getUntilLast (sStr, cSearch, false);
}
@Nullable
private static String _getUntilLast (@Nullable final String sStr,
@Nullable final String sSearch,
final boolean bIncludingSearchChar)
{
if (hasNoText (sSearch))
return "";
final int nIndex = getLastIndexOf (sStr, sSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (0, nIndex +
(bIncludingSearchChar ? sSearch.length () : 0));
}
/**
* Get everything from the string up to and including the first passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the empty string is
* returned.
*/
@Nullable
public static String getUntilLastIncl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getUntilLast (sStr, sSearch, true);
}
/**
* Get everything from the string up to and excluding the first passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the empty string is
* returned.
*/
@Nullable
public static String getUntilLastExcl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getUntilLast (sStr, sSearch, false);
}
@Nullable
private static String _getFromFirst (@Nullable final String sStr,
final char cSearch,
final boolean bIncludingSearchChar)
{
final int nIndex = getIndexOf (sStr, cSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (nIndex + (bIncludingSearchChar ? 0 : 1));
}
/**
* Get everything from the string from and including the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getFromFirstIncl (@Nullable final String sStr, final char cSearch)
{
return _getFromFirst (sStr, cSearch, true);
}
/**
* Get everything from the string from and excluding the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getFromFirstExcl (@Nullable final String sStr, final char cSearch)
{
return _getFromFirst (sStr, cSearch, false);
}
@Nullable
private static String _getFromFirst (@Nullable final String sStr,
@Nullable final String sSearch,
final boolean bIncludingSearchString)
{
if (hasNoText (sSearch))
return sStr;
final int nIndex = getIndexOf (sStr, sSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (nIndex +
(bIncludingSearchString ? 0 : sSearch.length ()));
}
/**
* Get everything from the string from and including the passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the input string is returned
* unmodified.
*/
@Nullable
public static String getFromFirstIncl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getFromFirst (sStr, sSearch, true);
}
/**
* Get everything from the string from and excluding the passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the input string is returned
* unmodified.
*/
@Nullable
public static String getFromFirstExcl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getFromFirst (sStr, sSearch, false);
}
@Nullable
private static String _getFromLast (@Nullable final String sStr,
final char cSearch,
final boolean bIncludingSearchChar)
{
final int nIndex = getLastIndexOf (sStr, cSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (nIndex + (bIncludingSearchChar ? 0 : 1));
}
/**
* Get everything from the string from and including the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getFromLastIncl (@Nullable final String sStr, final char cSearch)
{
return _getFromLast (sStr, cSearch, true);
}
/**
* Get everything from the string from and excluding the first passed char.
*
* @param sStr
* The source string. May be null.
* @param cSearch
* The character to search.
* @return null if the passed string does not contain the search
* character.
*/
@Nullable
public static String getFromLastExcl (@Nullable final String sStr, final char cSearch)
{
return _getFromLast (sStr, cSearch, false);
}
@Nullable
private static String _getFromLast (@Nullable final String sStr,
@Nullable final String sSearch,
final boolean bIncludingSearchString)
{
if (hasNoText (sSearch))
return sStr;
final int nIndex = getLastIndexOf (sStr, sSearch);
return nIndex == STRING_NOT_FOUND ? null : sStr.substring (nIndex +
(bIncludingSearchString ? 0 : sSearch.length ()));
}
/**
* Get everything from the string from and including the passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the input string is returned
* unmodified.
*/
@Nullable
public static String getFromLastIncl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getFromLast (sStr, sSearch, true);
}
/**
* Get everything from the string from and excluding the passed string.
*
* @param sStr
* The source string. May be null.
* @param sSearch
* The string to search. May be null.
* @return null if the passed string does not contain the search
* string. If the search string is empty, the input string is returned
* unmodified.
*/
@Nullable
public static String getFromLastExcl (@Nullable final String sStr, @Nullable final String sSearch)
{
return _getFromLast (sStr, sSearch, false);
}
/**
* Get the first token up to (and excluding) the separating character.
*
* @param sStr
* The string to search. May be null.
* @param cSearch
* The search character.
* @return The passed string if no such separator token was found.
*/
@Nullable
public static String getFirstToken (@Nullable final String sStr, final char cSearch)
{
final int nIndex = getIndexOf (sStr, cSearch);
return nIndex == StringHelper.STRING_NOT_FOUND ? sStr : sStr.substring (0, nIndex);
}
/**
* Get the first token up to (and excluding) the separating string.
*
* @param sStr
* The string to search. May be null.
* @param sSearch
* The search string. May be null.
* @return The passed string if no such separator token was found.
*/
@Nullable
public static String getFirstToken (@Nullable final String sStr, @Nullable final String sSearch)
{
if (StringHelper.hasNoText (sSearch))
return sStr;
final int nIndex = getIndexOf (sStr, sSearch);
return nIndex == StringHelper.STRING_NOT_FOUND ? sStr : sStr.substring (0, nIndex);
}
/**
* Get the last token from (and excluding) the separating character.
*
* @param sStr
* The string to search. May be null.
* @param cSearch
* The search character.
* @return The passed string if no such separator token was found.
*/
@Nullable
public static String getLastToken (@Nullable final String sStr, final char cSearch)
{
final int nIndex = getLastIndexOf (sStr, cSearch);
return nIndex == StringHelper.STRING_NOT_FOUND ? sStr : sStr.substring (nIndex + 1);
}
/**
* Get the last token from (and excluding) the separating string.
*
* @param sStr
* The string to search. May be null.
* @param sSearch
* The search string. May be null.
* @return The passed string if no such separator token was found.
*/
@Nullable
public static String getLastToken (@Nullable final String sStr, @Nullable final String sSearch)
{
if (StringHelper.hasNoText (sSearch))
return sStr;
final int nIndex = getLastIndexOf (sStr, sSearch);
return nIndex == StringHelper.STRING_NOT_FOUND ? sStr : sStr.substring (nIndex + getLength (sSearch));
}
@Nullable
public static String getReverse (@Nullable final String sStr)
{
if (sStr == null)
return null;
final char [] aChars = sStr.toCharArray ();
if (aChars.length <= 1)
return sStr;
final char [] ret = new char [aChars.length];
for (int nSrc = aChars.length - 1, nDst = 0; nSrc != -1; nSrc--, nDst++)
ret[nDst] = aChars[nSrc];
return new String (ret);
}
/**
* Optimized remove method that removes a set of characters from an input
* string!
*
* @param sInputString
* The input string.
* @param aRemoveChars
* The characters to remove. May not be null.
* @return The version of the string without the passed characters or an empty
* String if the input string was null.
*/
@Nonnull
public static String removeMultiple (@Nullable final String sInputString, @Nonnull final char [] aRemoveChars)
{
ValueEnforcer.notNull (aRemoveChars, "RemoveChars");
// Any input text?
if (hasNoText (sInputString))
return "";
// Anything to remove?
if (aRemoveChars.length == 0)
return sInputString;
// Get char array
final StringBuilder aSB = new StringBuilder (sInputString.length ());
final char [] aInput = sInputString.toCharArray ();
input: for (final char cInput : aInput)
{
for (final char cRemove : aRemoveChars)
if (cInput == cRemove)
continue input;
aSB.append (cInput);
}
return aSB.toString ();
}
}