Add StringUtils.containsAnyIgnoreCase(CharSequence, CharSequence...).

This commit is contained in:
Gary Gregory 2020-11-13 10:30:08 -05:00
parent 6a991d8413
commit 93d520a3e1
4 changed files with 129 additions and 95 deletions

View File

@ -55,6 +55,7 @@ The <action> type attribute can be add,update,fix,remove.
<!-- ADDS -->
<action type="add" dev="ggregory" due-to="Gary Gregory">Add BooleanUtils.booleanValues().</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add BooleanUtils.primitiveValues().</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add StringUtils.containsAnyIgnoreCase(CharSequence, CharSequence...).</action>
<action type="add" dev="ggregory" due-to="Edgar Asatryan">More test coverage for CharSequenceUtils. #631.</action>
<!-- UPDATES -->
<action type="update" dev="chtompki">Bump junit-jupiter from 5.6.2 to 5.7.0.</action>

View File

@ -30,6 +30,8 @@ import java.util.Set;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import org.apache.commons.lang3.function.ToBooleanBiFunction;
/**
* <p>Operations on {@link java.lang.String} that are
* {@code null} safe.</p>
@ -184,8 +186,6 @@ public class StringUtils {
*/
private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
// Abbreviating
//-----------------------------------------------------------------------
/**
* <p>Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "Now is the time for..."</p>
@ -559,8 +559,6 @@ public class StringUtils {
return new String(newCodePoints, 0, outOffset);
}
// Centering
//-----------------------------------------------------------------------
/**
* <p>Centers a String in a larger String of size {@code size}
* using the space character (' ').</p>
@ -669,8 +667,6 @@ public class StringUtils {
return str;
}
// Chomping
//-----------------------------------------------------------------------
/**
* <p>Removes one newline from end of a String if it's there,
* otherwise leave it alone. A newline is &quot;{@code \n}&quot;,
@ -754,8 +750,6 @@ public class StringUtils {
return removeEnd(str, separator);
}
// Chopping
//-----------------------------------------------------------------------
/**
* <p>Remove the last character from a String.</p>
*
@ -796,8 +790,6 @@ public class StringUtils {
return ret;
}
// Compare
//-----------------------------------------------------------------------
/**
* <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
* <ul>
@ -1003,8 +995,6 @@ public class StringUtils {
return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
}
// Contains
//-----------------------------------------------------------------------
/**
* <p>Checks if CharSequence contains a search character, handling {@code null}.
* This method uses {@link String#indexOf(int)} if possible.</p>
@ -1032,8 +1022,6 @@ public class StringUtils {
return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
}
// ContainsAny
//-----------------------------------------------------------------------
/**
* <p>Checks if the CharSequence contains any character in the given
* set of characters.</p>
@ -1128,11 +1116,13 @@ public class StringUtils {
}
/**
* <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
* <p>
* Checks if the CharSequence contains any of the CharSequences in the given array.
* </p>
*
* <p>
* A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
* length search array will return {@code false}.
* A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
* return {@code false}.
* </p>
*
* <pre>
@ -1147,17 +1137,71 @@ public class StringUtils {
*
*
* @param cs The CharSequence to check, may be null
* @param searchCharSequences The array of CharSequences to search for, may be null.
* Individual CharSequences may be null as well.
* @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
* null as well.
* @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
* @since 3.4
*/
public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
return containsAny(StringUtils::contains, cs, searchCharSequences);
}
/**
* <p>
* Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
* </p>
*
* <p>
* A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
* return {@code false}.
* </p>
*
* <pre>
* StringUtils.containsAny(null, *) = false
* StringUtils.containsAny("", *) = false
* StringUtils.containsAny(*, null) = false
* StringUtils.containsAny(*, []) = false
* StringUtils.containsAny("abcd", "ab", null) = true
* StringUtils.containsAny("abcd", "ab", "cd") = true
* StringUtils.containsAny("abc", "d", "abc") = true
* StringUtils.containsAny("abc", "D", "ABC") = true
* StringUtils.containsAny("ABC", "d", "abc") = true
* </pre>
*
*
* @param cs The CharSequence to check, may be null
* @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
* null as well.
* @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
* @since 3.12
*/
public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
}
/**
* <p>
* Checks if the CharSequence contains any of the CharSequences in the given array.
* </p>
*
* <p>
* A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
* return {@code false}.
* </p>
*
* @param cs The CharSequence to check, may be null
* @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
* null as well.
* @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
* @since 3.12
*/
private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
final CharSequence cs, final CharSequence... searchCharSequences) {
if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
return false;
}
for (final CharSequence searchCharSequence : searchCharSequences) {
if (contains(cs, searchCharSequence)) {
if (test.applyAsBoolean(cs, searchCharSequence)) {
return true;
}
}
@ -1202,8 +1246,6 @@ public class StringUtils {
return false;
}
// ContainsNone
//-----------------------------------------------------------------------
/**
* <p>Checks that the CharSequence does not contain certain characters.</p>
*
@ -1287,8 +1329,6 @@ public class StringUtils {
return containsNone(cs, invalidChars.toCharArray());
}
// ContainsOnly
//-----------------------------------------------------------------------
/**
* <p>Checks if the CharSequence contains only certain characters.</p>
*
@ -1422,8 +1462,6 @@ public class StringUtils {
return count;
}
// Count matches
//-----------------------------------------------------------------------
/**
* <p>Counts how many times the substring appears in the larger string.
* Note that the code only counts non-overlapping matches.</p>
@ -1546,8 +1584,6 @@ public class StringUtils {
return str == null ? defaultStr : str;
}
// Delete
//-----------------------------------------------------------------------
/**
* <p>Deletes all whitespaces from a String as defined by
* {@link Character#isWhitespace(char)}.</p>
@ -1580,8 +1616,6 @@ public class StringUtils {
return new String(chs, 0, count);
}
// Difference
//-----------------------------------------------------------------------
/**
* <p>Compares two Strings, and returns the portion where they differ.
* More precisely, return the remainder of the second String,
@ -1734,8 +1768,6 @@ public class StringUtils {
return endsWith(str, suffix, true);
}
// Equals
//-----------------------------------------------------------------------
/**
* <p>Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters.</p>
@ -2257,8 +2289,6 @@ public class StringUtils {
return Math.round(jw * 100.0D) / 100.0D;
}
// Misc
//-----------------------------------------------------------------------
/**
* <p>Find the Levenshtein distance between two Strings.</p>
*
@ -2588,8 +2618,6 @@ public class StringUtils {
return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
}
// IndexOf
//-----------------------------------------------------------------------
/**
* Returns the index within {@code seq} of the first occurrence of
* the specified character. If a character with value
@ -2694,8 +2722,6 @@ public class StringUtils {
return CharSequenceUtils.indexOf(seq, searchChar, startPos);
}
// IndexOfAny chars
//-----------------------------------------------------------------------
/**
* <p>Search a CharSequence to find the first index of any
* character in the given set of characters.</p>
@ -2745,8 +2771,6 @@ public class StringUtils {
return INDEX_NOT_FOUND;
}
// IndexOfAny strings
//-----------------------------------------------------------------------
/**
* <p>Find the first index of any of a set of potential substrings.</p>
*
@ -2830,8 +2854,6 @@ public class StringUtils {
return indexOfAny(cs, searchChars.toCharArray());
}
// IndexOfAnyBut chars
//-----------------------------------------------------------------------
/**
* <p>Searches a CharSequence to find the first index of any
* character not in the given set of characters.</p>
@ -3279,8 +3301,6 @@ public class StringUtils {
return true;
}
// Character Tests
//-----------------------------------------------------------------------
/**
* <p>Checks if the CharSequence contains only Unicode letters.</p>
*
@ -3525,9 +3545,6 @@ public class StringUtils {
return true;
}
// Nested extraction
//-----------------------------------------------------------------------
/**
* <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
*
@ -3559,8 +3576,6 @@ public class StringUtils {
return true;
}
// Empty checks
//-----------------------------------------------------------------------
/**
* <p>Checks if a CharSequence is empty ("") or null.</p>
*
@ -4777,9 +4792,6 @@ public class StringUtils {
return buf.toString();
}
// Joining
//-----------------------------------------------------------------------
/**
* <p>Joins the elements of the provided array into a single String
* containing the provided list of elements.</p>
@ -4921,8 +4933,6 @@ public class StringUtils {
return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
}
// LastIndexOf
//-----------------------------------------------------------------------
/**
* Returns the index within {@code seq} of the last occurrence of
* the specified character. For values of {@code searchChar} in the
@ -5181,8 +5191,6 @@ public class StringUtils {
return ordinalIndexOf(str, searchStr, ordinal, true);
}
// Left/Right/Mid
//-----------------------------------------------------------------------
/**
* <p>Gets the leftmost {@code len} characters of a String.</p>
*
@ -5660,8 +5668,6 @@ public class StringUtils {
return index;
}
// Overlay
//-----------------------------------------------------------------------
/**
* <p>Overlays part of a String with another String.</p>
*
@ -6131,8 +6137,6 @@ public class StringUtils {
return RegExUtils.removePattern(source, regex);
}
// Remove
//-----------------------------------------------------------------------
/**
* <p>Removes a substring only if it is at the beginning of a source string,
* otherwise returns the source string.</p>
@ -6235,8 +6239,6 @@ public class StringUtils {
return new String(buf);
}
// Padding
//-----------------------------------------------------------------------
/**
* <p>Repeat a String {@code repeat} times to form a
* new String.</p>
@ -6294,9 +6296,6 @@ public class StringUtils {
}
}
// Conversion
//-----------------------------------------------------------------------
/**
* <p>Repeat a String {@code repeat} times to form a
* new String, with a String separator injected each time. </p>
@ -6499,8 +6498,6 @@ public class StringUtils {
return RegExUtils.replaceAll(text, regex, replacement);
}
// Replace, character based
//-----------------------------------------------------------------------
/**
* <p>Replaces all occurrences of a character in a String with another.
* This is a null-safe version of {@link String#replace(char, char)}.</p>
@ -6979,8 +6976,6 @@ public class StringUtils {
return replace(text, searchString, replacement, max, true);
}
// Replacing
//-----------------------------------------------------------------------
/**
* <p>Replaces a String with another String inside a larger String, once.</p>
*
@ -7083,8 +7078,6 @@ public class StringUtils {
return RegExUtils.replacePattern(source, regex, replacement);
}
// Reversing
//-----------------------------------------------------------------------
/**
* <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
*
@ -7281,8 +7274,6 @@ public class StringUtils {
}
}
// Rotating (circular shift)
//-----------------------------------------------------------------------
/**
* <p>Rotate (circular shift) a String of {@code shift} characters.</p>
* <ul>
@ -7326,8 +7317,6 @@ public class StringUtils {
return builder.toString();
}
// Splitting
//-----------------------------------------------------------------------
/**
* <p>Splits the provided text into an array, using whitespace as the
* separator.
@ -8138,8 +8127,6 @@ public class StringUtils {
return startsWith(str, prefix, true);
}
// Stripping
//-----------------------------------------------------------------------
/**
* <p>Strips whitespace from the start and end of a String.</p>
*
@ -8228,8 +8215,6 @@ public class StringUtils {
return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
}
// StripAll
//-----------------------------------------------------------------------
/**
* <p>Strips whitespace from the start and end of every String in an array.
* Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
@ -8436,8 +8421,6 @@ public class StringUtils {
return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
}
// Substring
//-----------------------------------------------------------------------
/**
* <p>Gets a substring from the specified String avoiding exceptions.</p>
*
@ -8628,9 +8611,6 @@ public class StringUtils {
return str.substring(pos + separator.length());
}
// startsWith
//-----------------------------------------------------------------------
/**
* <p>Gets the substring after the last occurrence of a separator.
* The separator is not returned.</p>
@ -8711,8 +8691,6 @@ public class StringUtils {
return str.substring(pos + separator.length());
}
// SubStringAfter/SubStringBefore
//-----------------------------------------------------------------------
/**
* <p>Gets the substring before the first occurrence of a separator.
* The separator is not returned.</p>
@ -8792,8 +8770,6 @@ public class StringUtils {
return str.substring(0, pos);
}
// Substring between
//-----------------------------------------------------------------------
/**
* <p>Gets the String that is nested in between two instances of the
* same String.</p>
@ -8819,9 +8795,6 @@ public class StringUtils {
return substringBetween(str, tag, tag);
}
// endsWith
//-----------------------------------------------------------------------
/**
* <p>Gets the String that is nested in between two Strings.
* Only the first match is returned.</p>
@ -9060,8 +9033,6 @@ public class StringUtils {
return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
}
// Trim
//-----------------------------------------------------------------------
/**
* <p>Removes control characters (char &lt;= 32) from both
* ends of this String, handling {@code null} by returning
@ -9388,8 +9359,6 @@ public class StringUtils {
return str;
}
// Case conversion
//-----------------------------------------------------------------------
/**
* <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
*

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.function;
import java.util.function.BiFunction;
/**
* A function that accepts two arguments and produces a boolean result. This is the {@code boolean}-producing primitive
* specialization for {@link BiFunction}.
*
* @param <T> the type of the first argument to the function.
* @param <U> the type of the second argument to the function.
*
* @see BiFunction
* @since 3.12
*/
@FunctionalInterface
public interface ToBooleanBiFunction<T, U> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument.
* @param u the second function argument.
* @return the function result.
*/
boolean applyAsBoolean(T t, U u);
}

View File

@ -196,6 +196,27 @@ public class StringUtilsContainsTest {
assertTrue(StringUtils.containsAny("abc", "d", "abc"));
}
@Test
public void testContainsAnyIgnoreCase_StringStringArray() {
assertFalse(StringUtils.containsAnyIgnoreCase(null, (String[]) null));
assertFalse(StringUtils.containsAnyIgnoreCase(null, new String[0]));
assertFalse(StringUtils.containsAnyIgnoreCase(null, new String[] { "hello" }));
assertFalse(StringUtils.containsAnyIgnoreCase("", (String[]) null));
assertFalse(StringUtils.containsAnyIgnoreCase("", new String[0]));
assertFalse(StringUtils.containsAnyIgnoreCase("", new String[] { "hello" }));
assertFalse(StringUtils.containsAnyIgnoreCase("hello, goodbye", (String[]) null));
assertFalse(StringUtils.containsAnyIgnoreCase("hello, goodbye", new String[0]));
assertTrue(StringUtils.containsAnyIgnoreCase("hello, goodbye", new String[]{"hello", "goodbye"}));
assertTrue(StringUtils.containsAnyIgnoreCase("hello, goodbye", new String[]{"hello", "Goodbye"}));
assertTrue(StringUtils.containsAnyIgnoreCase("hello, goodbye", new String[]{"Hello", "Goodbye"}));
assertTrue(StringUtils.containsAnyIgnoreCase("hello, goodbye", new String[]{"Hello", null}));
assertTrue(StringUtils.containsAnyIgnoreCase("hello, null", new String[] { "Hello", null }));
// Javadoc examples:
assertTrue(StringUtils.containsAnyIgnoreCase("abcd", "ab", null));
assertTrue(StringUtils.containsAnyIgnoreCase("abcd", "ab", "cd"));
assertTrue(StringUtils.containsAnyIgnoreCase("abc", "d", "abc"));
}
/**
* See http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html
*/