542

I have two Strings, str1 and str2. How do I check if str2 is contained within str1, ignoring case?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
trinity
  • 9,806
  • 10
  • 46
  • 65
  • 1
    Both indexOf and contains go character by character, so if you need faster string searching (which you can get), then you would need to implement one of many published algorithms. – Stefan Kendall Feb 16 '10 at 17:55
  • 2
    I have the same question here is the answer:) http://stackoverflow.com/a/86832/621951 – Günay Gültekin Apr 08 '13 at 20:19

6 Answers6

1050
str1.toLowerCase().contains(str2.toLowerCase())
Igor Artamonov
  • 34,120
  • 8
  • 74
  • 106
136

How about matches()?

String string = "Madam, I am Adam";

// Starts with
boolean  b = string.startsWith("Mad");  // true

// Ends with
b = string.endsWith("dam");             // true

// Anywhere
b = string.indexOf("I am") >= 0;        // true

// To ignore case, regular expressions must be used

// Starts with
b = string.matches("(?i)mad.*");

// Ends with
b = string.matches("(?i).*adam");

// Anywhere
b = string.matches("(?i).*i am.*");
cs95
  • 274,032
  • 76
  • 480
  • 537
Jim Raynor
  • 2,178
  • 2
  • 28
  • 36
  • 14
    Your "indexOf" example should use >= 0, not > 0, since 0 is valid if the substring occurs at the beginning of the string. (Doesn't in your example, but could in other cases.) Added this response since people are obviously still searching and finding this answer. – Andrew Cottrell Aug 20 '13 at 16:59
  • Great answer! This is really useful! – Michael Lossagk Jan 28 '20 at 12:02
33

If you are able to use org.apache.commons.lang.StringUtils, I suggest using the following:

String container = "aBcDeFg";
String content = "dE";
boolean containerContainsContent = StringUtils.containsIgnoreCase(container, content);
Bojangles
  • 91,543
  • 47
  • 160
  • 197
Mojo
  • 331
  • 3
  • 2
21

You can use the toLowerCase() method:

public boolean contains( String haystack, String needle ) {
  haystack = haystack == null ? "" : haystack;
  needle = needle == null ? "" : needle;

  // Works, but is not the best.
  //return haystack.toLowerCase().indexOf( needle.toLowerCase() ) > -1

  return haystack.toLowerCase().contains( needle.toLowerCase() )
}

Then call it using:

if( contains( str1, str2 ) ) {
  System.out.println( "Found " + str2 + " within " + str1 + "." );
}

Notice that by creating your own method, you can reuse it. Then, when someone points out that you should use contains instead of indexOf, you have only a single line of code to change.

Dave Jarvis
  • 28,853
  • 37
  • 164
  • 291
Vincent Ramdhanie
  • 98,815
  • 22
  • 134
  • 183
10

I also favor the RegEx solution. The code will be much cleaner. I would hesitate to use toLowerCase() in situations where I knew the strings were going to be large, since strings are immutable and would have to be copied. Also, the matches() solution might be confusing because it takes a regular expression as an argument (searching for "Need$le" cold be problematic).

Building on some of the above examples:

public boolean containsIgnoreCase( String haystack, String needle ) {
  if(needle.equals(""))
    return true;
  if(haystack == null || needle == null || haystack .equals(""))
    return false; 

  Pattern p = Pattern.compile(needle,Pattern.CASE_INSENSITIVE+Pattern.LITERAL);
  Matcher m = p.matcher(haystack);
  return m.find();
}

example call: 

String needle = "Need$le";
String haystack = "This is a haystack that might have a need$le in it.";
if( containsIgnoreCase( haystack, needle) ) {
  System.out.println( "Found " + needle + " within " + haystack + "." );
}

(Note: you might want to handle NULL and empty strings differently depending on your needs. I think they way I have it is closer to the Java spec for strings.)

Speed critical solutions could include iterating through the haystack character by character looking for the first character of the needle. When the first character is matched (case insenstively), begin iterating through the needle character by character, looking for the corresponding character in the haystack and returning "true" if all characters get matched. If a non-matched character is encountered, resume iteration through the haystack at the next character, returning "false" if a position > haystack.length() - needle.length() is reached.

Michael Cooper
  • 101
  • 1
  • 2
  • 2
    I would do: `Pattern.CASE_INSENSITIVE|Pattern.LITERAL` – mike jones Nov 08 '13 at 18:08
  • @mikejones How can I check this for only words ? Consider the case below 1) "This is a haystack that might have a need$le in it."; 2) "This is a haystack that might have a need$lesss in it."; I want only case 1 to be matched as in that case need$le is present as a word. I don't want the 2nd case to be matched. How can I achieve this ? – KK_07k11A0585 Jul 06 '15 at 11:02
7

I'd use a combination of the contains method and the toUpper method that are part of the String class. An example is below:

String string1 = "AAABBBCCC"; 
String string2 = "DDDEEEFFF";
String searchForThis = "AABB";

System.out.println("Search1="+string1.toUpperCase().contains(searchForThis.toUpperCase()));

System.out.println("Search2="+string2.toUpperCase().contains(searchForThis.toUpperCase()));

This will return:

Search1=true
Search2=false

freedev
  • 17,230
  • 4
  • 83
  • 98
SOA Nerd
  • 943
  • 5
  • 12
  • 5
    Won't work. Some weird, international characters are converted to multiple characters when converted to lower-/upper-case. For example: `"ß".toUpperCase().equals("SS")` – Simon Apr 05 '13 at 22:36
  • 2
    That would figure. That's how a double s is written in German. – James P. Aug 05 '14 at 20:28