ฉันจะทำให้กรณีเปรียบเทียบสตริงของฉันไม่คำนึงถึงได้อย่างไร


112

ฉันสร้างโปรแกรม Java เพื่อเปรียบเทียบสองสตริง:

String s1 = "Hello";
String s2 = "hello";

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

จะแสดงคำว่า "ยินดีต้อนรับ" ฉันเข้าใจว่ามันเป็นเรื่องละเอียดอ่อน แต่ปัญหาของฉันคือฉันต้องการเปรียบเทียบสองสตริงโดยไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ haiคือผมคาดว่าการส่งออกจะเป็น


3
หากคุณทราบว่าเป็นกรณีที่คำนึงถึงตัวพิมพ์เล็กหรือใหญ่คุณสามารถแปลงเป็นตัวพิมพ์เล็กหรือตัวพิมพ์ใหญ่ก่อนที่จะเปรียบเทียบ
fastcodejava

หากคุณใช้s1.equalsIgnoreCase(s2)คุณอาจทำไม่ได้ทุกที่ที่ต้องทำ ฉันขอแนะนำให้คุณหาที่มาของสตริง - ไฟล์หรือฐานข้อมูลหรืออินพุตของผู้ใช้ - และแปลงเป็นตัวพิมพ์ใหญ่ (หรือตัวพิมพ์เล็ก) และใช้ต่อไปเพื่อเปรียบเทียบ
H2ONaCl

2
อย่าแปลงเป็นตัวล่าง / ตัวพิมพ์ใหญ่ (ตามที่แนะนำโดยความคิดเห็นด้านบน) ให้ใช้equalsIgnoreCaseแนวทางที่ยอมรับ อ่านเกี่ยวกับปัญหา Turkish I และปัญหา Unicode ที่คล้ายกันเพื่อดูเหตุผล
Ohad Schneider

1
@OhadSchneider equalsIgnoreCaseส่งคืนค่าที่ไม่ถูกต้องสำหรับภาษาตุรกีเพราะจะส่งกลับค่าจริงสำหรับการเปรียบเทียบ "i" และ "I" แม้ว่าจะส่งคืนค่าเท็จก็ตาม ดังนั้นฉันจึงสงสัยว่าถ้าคุณต้องการคำนึงถึงสถานที่Collatorตั้งจริง ๆ แล้วa เป็นวิธีที่จะไป
Trejkaz

1
@OhadSchneider ฉันสงสัย มันบอกว่าการทำต่ออักขระให้ผลลัพธ์เหมือนกัน แต่การทำtoLowerCase/ toUpperCaseบนสตริงทั้งหมดและการทำต่ออักขระก็ให้ผลลัพธ์ที่แตกต่างกันสองแบบเช่นกัน
Trejkaz

คำตอบ:


172
  • สิ่งที่ดีที่สุดคือการใช้s1.equalsIgnoreCase(s2): (ดูjavadoc )
  • คุณยังสามารถแปลงเป็นตัวพิมพ์ใหญ่ / ตัวพิมพ์เล็กและใช้งานได้ s1.equals(s2)

39
โปรดทราบว่าโซลูชันทั้งสองไม่จำเป็นต้องเหมือนกันสำหรับทุกภาษา String # equalsIgnoreCase ไม่ได้ใช้กฎการปลอกเฉพาะโลแคลในขณะที่ String # toLowerCase และ #toUpperCase ทำ
jarnbjo

1
@jarnbjo คุณช่วยยกตัวอย่างได้ไหมว่าความแตกต่างนั้นตรงไหน?
towi

16
อย่างน้อยก็มีการใช้กฎกรณีเฉพาะของสถานที่สำหรับภาษาตุรกีและภาษาเยอรมัน ภาษาตุรกีถือว่า I มีและไม่มีจุดเป็นตัวอักษรสองตัวที่แตกต่างกันสร้างคู่ตัวพิมพ์เล็ก / ใหญ่iİและıIในขณะที่ภาษาอื่นถือว่า iI เป็นคู่และไม่ใช้ตัวอักษรıและİ ในภาษาเยอรมันตัวพิมพ์เล็กßจะเป็นตัวพิมพ์ใหญ่ "SS"
jarnbjo


24

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อาจจำเป็นต้องทำงานเพิ่มขึ้นเล็กน้อย)


22

คุณต้องใช้compareToIgnoreCaseวิธีการของStringวัตถุ

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)มันหมายถึงความเท่าเทียมstr1str2


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");

คือสิ่งที่คุณต้องการสำหรับการตรวจสอบความเท่าเทียมกันอย่างแท้จริงในรหัสของคุณเอง

เพียงเพื่อให้ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่เกี่ยวข้องกับความเท่าเทียมกันของ Strings ใน Java ฟังก์ชัน hashCode () ของคลาส java.lang.String "is case sensitive":

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 กับ Strings เป็นคีย์และมีคีย์เช่น "SomeKey", "SOMEKEY" และ "somekey" เท่ากันคุณจะต้องรวมสตริงของคุณในคลาสอื่น (คุณไม่สามารถขยาย สตริงเนื่องจากเป็นคลาสสุดท้าย) ตัวอย่างเช่น :

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

อ็อบเจ็กต์ Null String ไม่สามารถเรียกใช้เมธอดเท่ากับ

กล่าวคือ:

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

เพื่อให้เป็น nullsafe คุณสามารถใช้

org.apache.commons.lang.StringUtils.equalsIgnoreCase(String, String)

หรือ

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

-6
public boolean newEquals(String str1, String str2)
{
    int len = str1.length();
int len1 = str2.length();
if(len==len1)
{
    for(int i=0,j=0;i<str1.length();i++,j++)
    {
        if(str1.charAt(i)!=str2.charAt(j))
        return false;
    }`enter code here`
}
return true;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.