在Java中,如何检查一个字符串是否包含一个子字符串(忽略大小写)?

563

我有两个字符串,str1str2。如何检查是否忽略大小写地包含str2str1中?


1
indexOf和contains都是逐个字符进行比较的,因此如果您需要更快的字符串搜索(可以实现),那么您需要实现许多已发布算法中的其中之一。 - Stefan Kendall
2
我有同样的问题,这里是答案 :) https://dev59.com/SHVD5IYBdhLWcg3wGXpI#86832 - Günay Gültekin
6个回答

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

更新:

原回答使用了 toLowerCase() 方法。但是正如一些人正确指出的那样,Unicode 中存在一些异常情况,最好使用 toUpperCase()。因为:

有些语言存在一个大写变体对应多个小写变体的情况。


7
某些原因导致我在调用"2014-03-25T17:55:00".contains("T")时返回了false。 - Jeremy List
3
有没有能够返回包含字符串(str2)的位置的函数? - RadijatoR
6
@RadijatoR 是的,它被称为indexOf,例如 int pos = str1.indexOf(str2) 或者不区分大小写 int pos = str1.toLowerCase().indexOf(str2.toLowerCase()) - Igor Artamonov
1
现在似乎可以工作了。之前发生了什么我也不知道。代码没有变化。 - frostymarvelous
2
@JeremyList http://ideone.com/weYI1e 它会打印出 true - MartyIX
显示剩余5条评论

139

那么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.*");

15
你的“indexOf”示例应该使用“>=0”而不是“>0”,因为如果子字符串出现在字符串的开头,0是有效的。虽然在你的示例中没有发生这种情况,但在其他情况下可能会发生。 - Andrew Cottrell
很棒的答案!这真的很有用! - Michael

35
如果您能使用 org.apache.commons.lang.StringUtils,我建议使用以下代码:
String container = "aBcDeFg";
String content = "dE";
boolean containerContainsContent = StringUtils.containsIgnoreCase(container, content);

22
你可以使用 toLowerCase() 方法:
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() )
}

然后使用以下方式调用:

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

请注意,通过创建自己的方法,您可以重复使用它。因此,当有人指出您应该使用contains而不是indexOf时,您只需要更改一行代码。


5
请记得添加关于当传递空对象时的行为的 Javadoc。 - Thorbjørn Ravn Andersen

10

我也赞同使用正则表达式的解决方案。代码将更加简洁。在我知道字符串将会很大的情况下,我不愿使用 toLowerCase(),因为字符串是不可变的,需要进行复制。另外,matches() 的解决方案可能会让人感到困惑,因为它将正则表达式作为参数(搜索 "Need$le" 可能会有问题)。

结合以上几个示例:

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 + "." );
}
(注:您可能想根据您的需求以不同方式处理 NULL 和空字符串。我认为我所做的方式更接近 Java 字符串规范。)
速度至关重要的解决方案可能包括通过逐个字符迭代搜索草堆,寻找针头的第一个字符。当匹配第一个字符(不区分大小写)时,开始逐个字符地迭代针头,查找草堆中对应的字符,并在所有字符都匹配时返回"true"。如果遇到不匹配的字符,则恢复迭代草堆下一个字符,如果达到位置 > haystack.length() - needle.length(),则返回"false"。

2
我会这样写:Pattern.CASE_INSENSITIVE|Pattern.LITERAL - mike jones
@mikejones 我怎样才能仅检查单词?考虑下面的情况: 1)“这是可能有need$le的干草堆。” 2)“这是可能有need$less的干草堆。”我只想匹配第一种情况,因为在那种情况下need$le作为一个单词存在。我不希望第二种情况被匹配。我该如何实现这个? - KK_07k11A0585

7
我会使用字符串类中的contains方法和toUpper方法的组合。以下是一个示例:
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()));

这将返回:

搜索1=true
搜索2=false


5
不起作用。一些奇怪的国际字符在转换为小写或大写时会转换为多个字符。例如:"ß".toUpperCase().equals("SS") - Simon
2
那就是这样。这就是德语中写双 s 的方式。 - James P.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接