选项忽略大小写与。包含方法? ?

.contains()方法有忽略大小写的选项吗?

我有一个 ArrayList的 DVD 对象。每个 DVD 对象都有几个元素,其中一个是标题。我有一个搜索特定标题的方法。有用,但我希望不要太大小写。

202398 次浏览

You can't guarantee that you're always going to get String objects back, or that the object you're working with in the List implements a way to ignore case.

If you do want to compare Strings in a collection to something independent of case, you'd want to iterate over the collection and compare them without case.

String word = "Some word";
List<String> aList = new ArrayList<>(); // presume that the list is populated


for(String item : aList) {
if(word.equalsIgnoreCase(item)) {
// operation upon successful match
}
}

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.

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:

  1. Learn the Collator and CollationKey classes.
  2. 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.
  3. Use a database. If it supports case-insensitive collations, declare the title column of the DVD table that way. Use JDBC or Hibernate or JPA or Spring Data, whichever you choose.
  4. If the database supports advanced text search, like Oracle, use that.
  5. Back in the Java world, use Apache Lucene and possibly Apache Solr.
  6. 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.

 private List<String> FindString(String stringToLookFor, List<String> arrayToSearchIn)
{
List<String> ReceptacleOfWordsFound = new ArrayList<String>();


if(!arrayToSearchIn.isEmpty())
{
for(String lCurrentString : arrayToSearchIn)
{
if(lCurrentString.toUpperCase().contains(stringToLookFor.toUpperCase())
ReceptacleOfWordsFound.add(lCurrentString);
}
}
return ReceptacleOfWordsFound;
}
private boolean containsIgnoreCase(List<String> list, String soughtFor) {
for (String current : list) {
if (current.equalsIgnoreCase(soughtFor)) {
return true;
}
}
return false;
}

The intuitive solution to transform both operands to lower case (or upper case) has the effect of instantiating an extra String object for each item which is not efficient for large collections. Also, regular expressions are an order of magnitude slower than simple characters comparison.

String.regionMatches() allows to compare two String regions in a case-insensitive way. Using it, it's possible to write an efficient version of a case-insensitive "contains" method. The following method is what I use; it's based on code from Apache commons-lang:

public static boolean containsIgnoreCase(final String str, final String searchStr) {
if (str == null || searchStr == null) {
return false;
}
final int len = searchStr.length();
final int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}

You can apply little trick over this.
Change all the string to same case: either upper or lower case
For C# Code:

List searchResults = sl.FindAll(s => s.ToUpper().Contains(seachKeyword.ToUpper()));

For Java Code:

import java.util.*;


class Test
{
public static void main(String[] args)
{
String itemCheck="check";
ArrayList<String> listItem =new ArrayList<String>();
listItem.add("Check");
listItem.add("check");
listItem.add("CHeck");
listItem.add("Make");
listItem.add("CHecK");
for(String item :listItem)
{
if(item.toUpperCase().equals(itemCheck.toUpperCase()))
{
System.out.println(item);
}
}


}


}

If you're using Java 8

List<String> list = new ArrayList<>();


boolean containsSearchStr = list.stream().anyMatch("search_value"::equalsIgnoreCase);

In Java 8 you can use the Stream interface:

return dvdList.stream().anyMatch(d -> d.getTitle().equalsIgnoreCase("SomeTitle"));

For Java 8, You can have one more solution like below

List<String> list = new ArrayList<>();
String searchTerm = "dvd";


if(String.join(",", list).toLowerCase().contains(searchTerm)) {
System.out.println("Element Present!");
}

If you are looking for contains & not equals then i would propose below solution. Only drawback is if your searchItem in below solution is "DE" then also it would match

    List<String> list = new ArrayList<>();
public static final String[] LIST_OF_ELEMENTS = { "ABC", "DEF","GHI" };
String searchItem= "def";


if(String.join(",", LIST_OF_ELEMENTS).contains(searchItem.toUpperCase())) {
System.out.println("found element");
break;
}

With a null check on the dvdList and your searchString

    if (!StringUtils.isEmpty(searchString)) {
return Optional.ofNullable(dvdList)
.map(Collection::stream)
.orElse(Stream.empty())
.anyMatch(dvd >searchString.equalsIgnoreCase(dvd.getTitle()));
}

I know I'm a little late to the party but in Kotlin you can easily use:

fun Collection<String>.containsIgnoreCase(item: String) = any {
it.equals(item, ignoreCase = true)
}




val list = listOf("Banana")


println(list.contains("banana"))
println(list.containsIgnoreCase("BaNaNa"))

Kotlin Devs, go with any / none

private fun compareCategory(
categories: List<String>?,
category: String
) = categories?.any { it.equals(category, true) } ?: false

For Java 8+, I recommend to use following library method.

org.apache.commons.lang3.StringUtils

list.stream()
.filter(text -> StringUtils.containsIgnoreCase(text, textToSearch))

It's very simple using the power of Kotlin's extension function, this answer may help Java and Kotlin developers.

inline fun List<String>.contains(text: String, ignoreCase: Boolean = false) = this.any { it.equals(text, ignoreCase) }


// Usage
list.contains("text", ignoreCase = true)

You can replace contains() for equalsIgnoreCase using stream() as below

    List<String> names = List.of("One","tWo", "ThrEe", "foUR", "five", "Six", "THREE");
boolean contains = names.stream().anyMatch(i -> i.equalsIgnoreCase("three"))
public List<DdsSpreadCoreBean>  filteredByGroupName(DdsSpreadCoreBean ddsSpreadFilterBean, List<DdsSpreadCoreBean> spreadHeaderList){


List<DdsSpreadCoreBean> filteredByGroupName = new ArrayList<>();
filteredByGroupName = spreadHeaderList.stream().
filter(s->s.getGroupName()
.toLowerCase
.contains(ddsSpreadFilterBean.getGroupName())).collect(Collectors.toList());
    

return filteredByGroupName;
}

Option to ignore case with .contains method? Check the below example

boolean contains = employeeTypes.stream().anyMatch(i -> i.equalsIgnoreCase(employeeType));

I added Custom Annotation for validation in my project

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = EmployeeTypeValidator.class)
public @interface ValidateEmployeeType {
public String message() default "Invalid employeeType: It should be either Permanent or Vendor";


Class<?>[] groups() default { };


Class<? extends Payload>[] payload() default { };
}

Validation of EmployeeType

public class EmployeeTypeValidator implements ConstraintValidator<ValidateEmployeeType, String> {


@Override
public boolean isValid(String employeeType, ConstraintValidatorContext constraintValidatorContext) {
List<String> employeeTypes = Arrays.asList("Permanent", "vendor", "contractual");
boolean contains = employeeTypes.stream().anyMatch(i -> i.equalsIgnoreCase(employeeType));
return contains;
}
}

Entity of Employee

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private int empId;
@NotBlank(message = "firstName shouldn't be null or empty")
private String firstName;
@NotBlank(message = "lastName shouldn't be null or empty")
private String lastName;
@Past(message = "start shouldn't be before current date")
@JsonFormat(pattern = "dd-MM-yyyy")
private Date doj;
@NotNull(message = "department shouldn't be null")
@NotEmpty(message = "department shouldn't be empty")
private String dept;
@Email(message = "invalid email id")
private String email;
@ValidateEmployeeType
private String employeeType;
}

For Validation, We need Dependency in pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>