Case-Insensitive String Matching in Java

1. Overview

There are many ways to check if a String contains a substring. In this article, we’ll be looking for substrings within a String while focusing on case-insensitive workarounds to String.contains() in Java. Most importantly, we’ll provide examples of how to solve this issue.

2. The Simplest Solution: String.toLowerCase

The simplest solution is by using String.toLowerCase(). In this case, we’ll transform both strings to lowercase and then use the contains() method:

assertTrue(src.toLowerCase().contains(dest.toLowerCase()));

We can also use String.toUpperCase() and it would provide the same result.

3. String.matches With Regular Expressions

Another option is by using String.matches() with regular expressions:

assertTrue(src.matches("(?i).*" + dest + ".*"));

The matches() method takes a String to represent the regular expression. (?i) enables case-insensitivity and .* uses every character except line breaks.

4. String.regionMatches

We can also use String.regionMatches(). It checks if two String regions match, using true for the ignoreCase parameter:

public static boolean processRegionMatches(String src, String dest) {
    for (int i = src.length() - dest.length(); i >= 0; i--) 
        if (src.regionMatches(true, i, dest, 0, dest.length())) 
            return true; 
    return false;
}
assertTrue(processRegionMatches(src, dest));

To improve the performance, it starts matching the region, taking into account the length of the destination String. Then, it diminishes the iterator.

5. Pattern With the CASE_INSENSITIVE Option

The java.util.regex.Pattern class provides us a way of matching strings using the matcher() method. In this case, we can use the quote() method to escape any special characters, and the CASE_INSENSITIVE flag. Let’s take a look:

assertTrue(Pattern.compile(Pattern.quote(dest), Pattern.CASE_INSENSITIVE)
    .matcher(src)
    .find());

6. Apache Commons StringUtils.containsIgnoreCase

Finally, we’ll take advantage of the Apache Commons StringUtils class:

assertTrue(StringUtils.containsIgnoreCase(src, dest));

7. Performance Comparison

As in this general article about checking for substrings using the contains method, we used the open-source framework Java Microbenchmark Harness (JMH) to compare the performance of the methods in nanoseconds:

  1. Pattern CASE_INSENSITIVE Regular Expression: 399.387 ns
  2. String toLowerCase: 434.064 ns
  3. Apache Commons StringUtils: 496.313 ns
  4. String Region Matches: 718.842 ns
  5. String matches with Regular Expression: 3964.346 ns

As we can see, the winner is Pattern with the CASE_INSENSITIVE flag enabled, closely followed by toLowerCase(). We also noticed a clear improvement in the performance between Java 8 and Java 11.

8. Conclusion

In this tutorial, we looked at a few different ways to check a String for a substring, while ignoring the case in Java.

We looked at using String.toLowerCase() and toUpperCase()String.matches()String.regionMatches(), Apache Commons StringUtils.containsIgnoreCase(), and Pattern.matcher().find().

Also, we evaluated the performance of each solution and found that using the compile() method from java.util.regex.Pattern with the CASE_INSENSITIVE flag performed the best.

As always, the code is available over on GitHub.