563

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
trinity
  • 10,394
  • 15
  • 49
  • 67
  • 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

1089
str1.toUpperCase().contains(str2.toUpperCase())

UPD:

Original answer was using toLowerCase() method. But as some people correctly noticed, there are some exceptions in Unicode and it's better to use toUpperCase(). Because:

There are languages knowing more than one lower case variant for one upper case variant.

Igor Artamonov
  • 35,450
  • 10
  • 82
  • 113
  • 7
    for some reason I'm getting false when I call "2014-03-25T17:55:00".contains("T") – Jeremy List Mar 25 '14 at 08:45
  • 3
    Is there function that returns and position where is occured that contain (str2) ? – RadijatoR Jun 23 '15 at 12:38
  • 6
    @RadijatoR yes, it's called indexOf, like `int pos = str1.indexOf(str2)` or case insensitive as `int pos = str1.toLowerCase().indexOf(str2.toLowerCase())` – Igor Artamonov Jun 23 '15 at 12:41
  • 1
    Seems to be working now. No idea what happened earlier. Same code. – frostymarvelous Aug 20 '15 at 23:38
  • @frostymarvelous i am having same issue, bug in java... i was trying to match "success" with "Successful".toLowerCase(), would fail, changed it to "ccess" and then it worked. very weird. strangely though, matching "SUCCESS" with "Successful".toUpperCase() also worked – Fonix Jan 08 '16 at 02:44
  • @Fonix which was str1 and which was str2? – frostymarvelous Jan 09 '16 at 15:09
  • @frostymarvelous "Successful" was str 1, so it was `"Successful".toLowerCase().contains("success");` ("Successful" was a variable i got back from a json response from server) – Fonix Jan 10 '16 at 16:06
  • 2
    @JeremyList http://ideone.com/weYI1e it prints `true`. – MartyIX May 11 '16 at 10:43
  • 1
    @JeremyList It prints true – Ricardo Jul 16 '17 at 16:18
  • This accepted answer is correct in suggesting `contains()`, but it has it backwards with using `toLowerCase()`. Ideally a locale-aware uppercase function should be used; if not possible or not desired, then **toUpperCase()** is preferable for normalizing strings. See https://stackoverflow.com/a/14128850/3665087 – j1elo Oct 15 '21 at 13:42
139

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
  • 379,657
  • 97
  • 704
  • 746
Jim Raynor
  • 2,268
  • 3
  • 31
  • 36
  • 15
    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
35

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
  • 99,427
  • 50
  • 170
  • 208
Mojo
  • 351
  • 3
  • 2
22

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
  • 30,436
  • 41
  • 178
  • 315
Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
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
  • 25,946
  • 8
  • 108
  • 125
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