如何使我的字符串比较不区分大小写?

118

我创建了一个Java程序来比较两个字符串:

String str = "Hello";

if (str.equals("hello")) {
    System.out.println("match");
} else {
    System.out.println("no match");
}

它是大小写敏感的。我怎样才能改变它,使其不区分大小写?


3
如果你知道大小写敏感,可以在比较之前将两个字符串都转换为小写或大写。 - fastcodejava
1
如果你使用s1.equalsIgnoreCase(s2),你可能会在需要执行的所有地方都失败。我建议你找出字符串来自哪里——文件、数据库或用户输入——然后将其转换为大写(或小写),并继续使用.equals进行比较。 - H2ONaCl
2
请勿将文本转换为小写或大写(如上面的评论所建议),请使用已接受的 equalsIgnoreCase 方法。请阅读土耳其语 I 问题和类似的 Unicode 问题以了解原理。 - Ohad Schneider
1
@OhadSchneider equalsIgnoreCase 对于土耳其语返回错误的值,因为它在比较 "i" 和 "I" 时返回 true,即使它应该返回 false。因此,我怀疑如果您想考虑区域设置,那么 Collator 实际上是正确的选择。 - Hakanai
1
@OhadSchneider 我在想。它说逐个字符执行会产生相同的结果,但是对整个字符串执行 toLowerCase / toUpperCase 和逐个字符执行会产生两个不同的结果。 - Hakanai
显示剩余3条评论
12个回答

188

最好的方法是使用str.equalsIgnoreCase("foo")。它专门针对这个目的进行了优化。

你也可以在使用equals比较之前将两个字符串转换为大写或小写。这是一个有用的技巧,值得记住,因为其他语言可能没有equalsIgnoreCase的等效功能。

str.toUpperCase().equals(str2.toUpperCase())

如果你使用的是非罗马字母表,请注意JavaDoc中equalsIgnoreCase这部分的内容,其中指出:

请注意,该方法不考虑语言环境,并且对于某些语言环境会导致不理想的结果Collator类提供了区域设置敏感的比较。


42
请注意,这两种解决方案不一定对所有语言环境都相同。String#equalsIgnoreCase 不使用特定于语言环境的大小写规则,而 String#toLowerCase 和 #toUpperCase 则使用。 - jarnbjo
1
@jarnbjo 你能给一个例子来说明这个差异吗? - towi
18
针对区域特定的大小写规则,至少在土耳其语和德语中已经实施。土耳其语将带有和没有点的"I"视为两个不同的字母,形成了iİ和ıI的大小写对,而其他语言将iI视为一对,并且不使用"ı"和"İ"这两个字母。在德语中,小写字母"ß"被大写为"SS"。 - jarnbjo

49

27

String.equalsIgnoreCase 是处理简单不区分大小写字符串比较最实用的选择。

但是,需要注意的是该方法既不能进行完整的大小写折叠,也不能进行分解,因此无法执行Unicode标准中指定的无大小写匹配。 实际上,JDK API没有提供访问大小写折叠字符数据的信息,因此最好将此任务委托给经过验证的第三方库。

这个库就是ICU,下面是如何实现一个用于不区分大小写字符串比较的实用程序:

import com.ibm.icu.text.Normalizer2;

// ...

public static boolean equalsIgnoreCase(CharSequence s, CharSequence t) {
    Normalizer2 normalizer = Normalizer2.getNFKCCasefoldInstance();
    return normalizer.normalize(s).equals(normalizer.normalize(t));
}

    String brook = "flu\u0308ßchen";
    String BROOK = "FLÜSSCHEN";

    assert equalsIgnoreCase(brook, BROOK);

仅使用String.equalsIgnoreCase或者将字符串转为大写或小写后使用String.equals进行比较,即使这个简单的测试都无法通过。

(需要注意的是,预定义的大小写折叠规则getNFKCCasefoldInstance不依赖于特定的语言环境;但对于土耳其地区,则需要更多涉及到UCharacter.foldCase的工作)。


23

您需要使用String对象的compareToIgnoreCase方法。

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)这意味着str1等于str2


10
import java.lang.String; //contains equalsIgnoreCase()
/*
*
*/
String s1 = "Hello";
String s2 = "hello";

if (s1.equalsIgnoreCase(s2)) {
System.out.println("hai");
} else {
System.out.println("welcome");
}

现在它将输出:hai


5

在默认的Java API中,您有:

String.CASE_INSENSITIVE_ORDER

因此,如果您要在排序数据结构中使用字符串,就不需要重写比较器。
String s = "some text here";
s.equalsIgnoreCase("Some text here");

您希望在自己的代码中进行纯等式检查。

仅为进一步了解有关Java中字符串相等性的信息。java.lang.String类的hashCode()函数“区分大小写”:

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

如果你想使用Hashtable/HashMap作为字符串键,并且希望"somekey"、"SomeKey"和"SOMEKEY"被视为相等的键,那么你必须将字符串包装在另一个类中(不能继承String,因为它是一个 final 类)。例如:

private static class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    private HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }
}

然后按如下方式使用它:
HashMap<HashWrap, Object> map = new HashMap<HashWrap, Object>();

2
请注意,在执行.equals或.equalsIgnoreCase之前,您可能需要对它们进行空值检查。
一个空的字符串对象不能调用equals方法。
例如:
public boolean areStringsSame(String str1, String str2)
{
    if (str1 == null && str2 == null)
        return true;
    if (str1 == null || str2 == null)
        return false;

    return str1.equalsIgnoreCase(str2);
}

1
注意:第二个和第三个语句可以合并成一个语句,像这样:if (str1 == null || str2 == null) return false; - LuckyMe
根据上面的评论修改了代码,使其更加简洁 - 今天真是漫长的一天 :) - VeenarM
1
你也可以将第一行改为if (str1 == str2) return true;,这既考虑了空值的情况,又避免了两个字符串引用指向同一个字符串对象的情况。 - Barney


1
为了保证 null 安全性,您可以使用:
org.apache.commons.lang.StringUtils.equalsIgnoreCase(String, String)

或者

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)

1

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