Option to ignore case with .contains method?
Is there an option to ignore case with .contains()
method?
I have an ArrayList
of DVD object. Each DVD object has a few elements, one of them is a title. And I have a method that searches for a specific title. It works, but I'd like it to be case insensitive.
If you're using Java 8
List<String> list = new ArrayList<>();
boolean containsSearchStr = list.stream().anyMatch("search_value"::equalsIgnoreCase);
I'm guessing you mean ignoring case when searching in a string?
I don't know any, but you could try to convert the string to search into either to lower or to upper case, then search.
// s is the String to search into, and seq the sequence you are searching for.
bool doesContain = s.toLowerCase().contains(seq);
Edit: As Ryan Schipper suggested, you can also (and probably would be better off) do seq.toLowerCase(), depending on your situation.
private boolean containsIgnoreCase(List<String> list, String soughtFor) {
for (String current : list) {
if (current.equalsIgnoreCase(soughtFor)) {
return true;
}
}
return false;
}
In Java 8 you can use the Stream interface:
return dvdList.stream().anyMatch(d -> d.getTitle().equalsIgnoreCase("SomeTitle"));
This probably isn't the best way for your particular problem, but you can use the String.matches(String regex)
method or the matcher equivalent. We just need to construct a regular expression from your prospective title. Here it gets complex.
List<DVD> matchingDvds(String titleFragment) {
String escapedFragment = Pattern.quote(titleFragment);
// The pattern may have contained an asterisk, dollar sign, etc.
// For example, M*A*S*H, directed by Robert Altman.
Pattern pat = Pattern.compile(escapedFragment, Pattern.CASE_INSENSITIVE);
List<DVD> foundDvds = new ArrayList<>();
for (DVD dvd: catalog) {
Matcher m = pat.matcher(dvd.getTitle());
if (m.find()) {
foundDvds.add(dvd);
}
}
return foundDvds;
}
But this is inefficient, and it's being done purely in Java. You would do better to try one of these techniques:
- Learn the
Collator
andCollationKey
classes. - If you have no choice but to stay in the Java world, add a method to DVD,
boolean matches(String fragment)
. Have the DVD tell you what it matches. - Use a database. If it supports case-insensitive collations, declare the
title
column of theDVD
table that way. Use JDBC or Hibernate or JPA or Spring Data, whichever you choose. - If the database supports advanced text search, like Oracle, use that.
- Back in the Java world, use
Apache Lucene
and possiblyApache Solr
. - Use a language tuned for case-insensitive matches.
If you can wait until Java 8, use lambda expressions. You can avoid the Pattern and Matcher class that I used above by building the regex this way:
String escapedFragment = Pattern.quote(titleFragment);
String fragmentAnywhereInString = ".*" + escapedFragment + ".*";
String caseInsensitiveFragment = "(?i)" + fragmentAnywhereInString;
// and in the loop, use:
if(dvd.getTitle().matches(caseInsensitiveFragment)) {
foundDvds.add(dvd);
}
But this compiles the pattern too many times. What about lower-casing everything?
if (dvd.getTitle().toLowerCase().contains(titleFragment.toLowerCase()))
Congratulations; you've just discovered the Turkish problem. Unless you state the locale in toLowerCase
, Java finds the current locale. And the lower-casing is slow because it has to take into account the Turkish dotless i and dotted I. At least you have no patterns and no matchers.