Bagaimana cara melakukan perbandingan string case insensitive?

1056

Bagaimana cara saya melakukan perbandingan string yang tidak sensitif huruf pada JavaScript?

flybywire
sumber
25
lihat .localeCompare()metode javascript yang baru ditambahkan . Hanya didukung oleh browser modern pada saat penulisan (IE11 +). lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Adrien Be
1
lihat juga stackoverflow.com/questions/51165/...
Adrien Be
5
@AdrienBe "A".localeCompare( "a" );kembali 1di Konsol Chrome 48.
manuell
3
@manuell yang berarti "a"datang sebelum "A"saat diurutkan. Seperti "a"datang sebelumnya "b". Jika perilaku ini tidak diinginkan, seseorang mungkin ingin .toLowerCase()setiap huruf / string. yaitu. "A".toLowerCase().localeCompare( "a".toLowerCase() )lihat developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Adrien Be
2
Karena perbandingan sering merupakan istilah yang digunakan untuk menyortir / memesan string saya kira. Saya sudah lama berkomentar di sini. ===akan memeriksa kesetaraan tetapi tidak akan cukup baik untuk menyortir / memesan string (lih. pertanyaan yang awalnya saya tautkan).
Adrien Jadilah

Jawaban:

1163

Cara termudah untuk melakukannya (jika Anda tidak khawatir tentang karakter Unicode khusus) adalah menelepon toUpperCase:

var areEqual = string1.toUpperCase() === string2.toUpperCase();
Slaks
sumber
44
Konversi ke huruf besar atau kecil memang memberikan perbandingan yang benar-benar tidak sensitif dalam semua bahasa. i18nguy.com/unicode/turkish-i18n.html
Samuel Neff
57
@ Sam: Saya tahu. Itu sebabnya saya menulis if you're not worried about special Unicode characters.
SLaks
141
Apakah ada alasan untuk memilih toUpperCaselebih toLowerCase?
jpmc26
19
Apakah ini benar-benar JS terbaik yang ditawarkan?
Kugel
210

EDIT : Jawaban ini awalnya ditambahkan 9 tahun yang lalu. Hari ini Anda harus menggunakan localeComparedengan sensitivity: 'accent'opsi:

function ciEquals(a, b) {
    return typeof a === 'string' && typeof b === 'string'
        ? a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0
        : a === b;
}

console.log("'a' = 'a'?", ciEquals('a', 'a'));
console.log("'AaA' = 'aAa'?", ciEquals('AaA', 'aAa'));
console.log("'a' = 'á'?", ciEquals('a', 'á'));
console.log("'a' = 'b'?", ciEquals('a', 'b'));

The { sensitivity: 'accent' }memberitahu localeCompare()untuk mengobati dua varian surat dasar yang sama sebagai yang sama kecuali mereka memiliki aksen yang berbeda (seperti dalam contoh ketiga) di atas.

Atau, Anda dapat menggunakan { sensitivity: 'base' }, yang memperlakukan dua karakter sebagai setara selama karakter dasarnya adalah sama (sehingga Aakan diperlakukan sebagai setara dengan á).

Perhatikan bahwa parameter ketiga localeComparetidak didukung di IE10 atau lebih rendah atau peramban seluler tertentu (lihat bagan kompatibilitas pada halaman yang ditautkan di atas), jadi jika Anda perlu mendukung peramban tersebut, Anda akan memerlukan semacam fallback:

function ciEqualsInner(a, b) {
    return a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0;
}

function ciEquals(a, b) {
    if (typeof a !== 'string' || typeof b !== 'string') {
        return a === b;
    }

    //      v--- feature detection
    return ciEqualsInner('A', 'a')
        ? ciEqualsInner(a, b)
        : /*  fallback approach here  */;
}

Jawaban asli

Cara terbaik untuk melakukan perbandingan kasus yang tidak sensitif dalam JavaScript adalah menggunakan match()metode RegExp dengan ibenderanya.

Pencarian case-sensitive

Ketika kedua string yang dibandingkan adalah variabel (bukan konstanta), maka itu sedikit lebih rumit karena Anda perlu membuat RegExp dari string tetapi meneruskan string ke konstruktor RegExp dapat menghasilkan kecocokan yang salah atau kecocokan yang gagal jika string memiliki regex khusus karakter di dalamnya.

Jika Anda peduli tentang internasionalisasi, jangan gunakan toLowerCase()atau toUpperCase()karena tidak memberikan perbandingan kasus-sensitif yang akurat dalam semua bahasa.

http://www.i18nguy.com/unicode/turkish-i18n.html

Samuel Neff
sumber
5
@Quandary, ya, itulah yang saya katakan harus ditangani - "Anda perlu membuat RegExp dari string tetapi meneruskan string ke konstruktor RegExp dapat menghasilkan pertandingan yang salah atau gagal jika string memiliki karakter regex khusus di dalamnya"
Samuel Neff
21
Menggunakan ini adalah solusi paling mahal untuk perbandingan string case-insensitive. RegExp dimaksudkan untuk pencocokan pola yang rumit, karena itu, perlu membangun pohon keputusan untuk setiap pola, kemudian menjalankannya terhadap string input. Sementara itu akan berhasil, itu sebanding dengan naik pesawat jet untuk pergi berbelanja di blok berikutnya. tl; dr: tolong jangan lakukan ini.
Agoston Horvath
2
saya bisa menggunakan localeCompare (), tetapi mengembalikan -1 untuk 'a'.localeCompare('A')dan seperti op saya sedang mencari membandingkan string case sensitif.
StingyJack
3
@StingyJack untuk melakukan perbandingan kasus-sensitif menggunakan localeCompare, Anda harus melakukan 'a'.localeCompare (' A ', tidak terdefinisi, {sensitivitas:' basis '})
Judah Gabriel Himango
1
Catatan: The localeCompareVersi mengharuskan mesin JavaScript mendukung API ECMAScript® Internasionalisasi , yang itu tidak diperlukan untuk melakukan. Jadi sebelum mengandalkannya, Anda mungkin ingin memeriksa apakah itu berfungsi di lingkungan yang Anda gunakan. Misalnya: const compareInsensitive = "x".localeCompare("X", undefined, {sensitivity: "base"}) === 0 ? (a, b) => a.localeCompare(b, undefined, {sensitivity: "base"}) : (a, b) => a.toLowerCase().localeCompare(b.toLowerCase());atau semacamnya.
TJ Crowder
47

Seperti yang dikatakan dalam komentar baru-baru ini, string::localeComparemendukung perbandingan kasus sensitif (antara hal-hal kuat lainnya).

Ini contoh sederhana

'xyz'.localeCompare('XyZ', undefined, { sensitivity: 'base' }); // returns 0

Dan fungsi generik yang bisa Anda gunakan

function equalsIgnoringCase(text, other) {
    return text.localeCompare(other, undefined, { sensitivity: 'base' }) === 0;
}

Perhatikan bahwa alih-alih undefinedAnda mungkin harus memasukkan lokal spesifik yang Anda gunakan untuk bekerja. Ini penting sebagaimana dinyatakan dalam dokumen MDN

dalam bahasa Swedia, ä dan a adalah huruf dasar yang terpisah

Opsi sensitivitas

Opsi sensitivitas ditabulasikan dari MDN

Dukungan browser

Pada saat pengeposan, UC Browser untuk Android dan Opera Mini tidak mendukung parameter lokal dan opsi . Silakan periksa https://caniuse.com/#search=localeCompare untuk info terkini.

Jay Wick
sumber
35

Dengan bantuan ekspresi reguler juga bisa kita raih.

(/keyword/i).test(source)

/iuntuk mengabaikan kasus. Jika tidak perlu, kita dapat mengabaikan dan menguji untuk TIDAK pertandingan yang sensitif seperti

(/keyword/).test(source)
SP007
sumber
17
Menggunakan regex seperti ini akan cocok dengan substring! Dalam contoh Anda string keyWORDakan menghasilkan hasil dalam kecocokan positif. Tetapi string this is a keyword yoatau keywordsjuga akan menghasilkan kecocokan positif. Sadarilah itu :-)
Elmer
6
Ini tidak menjawab pemeriksaan Kesetaraan (tidak sensitif huruf besar) seperti yang ditanyakan dalam pertanyaan! Tapi, ini cek Berisi ! Jangan gunakan itu
S.Serpooshan
4
Tentu saja, untuk mencocokkan seluruh string, regexp dapat diubah menjadi /^keyword$/.test(source), tetapi 1) jika keywordbukan konstanta, Anda harus melakukannya new RegExp('^' + x + '$').test(source)dan 2) beralih ke regexp untuk menguji sesuatu yang sederhana seperti kesetaraan string case-insensitive. sama sekali tidak sangat efisien.
JHH
28

Ingatlah bahwa casing adalah operasi khusus lokal. Bergantung pada skenario, Anda mungkin ingin mempertimbangkannya. Misalnya, jika Anda membandingkan nama dua orang, Anda mungkin ingin mempertimbangkan lokal tetapi jika Anda membandingkan nilai yang dihasilkan mesin seperti UUID maka Anda mungkin tidak. Ini sebabnya saya menggunakan fungsi berikut di perpustakaan utils saya (perhatikan bahwa pengecekan tipe tidak termasuk untuk alasan kinerja).

function compareStrings (string1, string2, ignoreCase, useLocale) {
    if (ignoreCase) {
        if (useLocale) {
            string1 = string1.toLocaleLowerCase();
            string2 = string2.toLocaleLowerCase();
        }
        else {
            string1 = string1.toLowerCase();
            string2 = string2.toLowerCase();
        }
    }

    return string1 === string2;
}
Shital Shah
sumber
Apakah ada alasan Anda menggunakan "!!" untuk melakukan konversi boolean eksplisit, alih-alih membiarkan klausa if untuk mengevaluasi kebenaran nilai-nilai?
Celos
Itu tidak wajib. Saya kira saya mendapatkannya dari versi saya yang lain dari kode yang lebih rumit. Saya telah memperbarui jawabannya.
Shital Shah
@thekodester fungsi Anda memiliki bug. Ini compareStrings("", "")akan memberi falsemeskipun fakta string sama.
Sergey
@Sergey Melakukan itu kembali trueuntuk saya. Mungkin itu adalah bug pada browser Anda?
Jenna Sloan
14

Saya baru-baru ini membuat perpustakaan mikro yang menyediakan pembantu string case-insensitive: https://github.com/nickuraltsev/ignore-case . (Ini menggunakan toUpperCaseinternal.)

var ignoreCase = require('ignore-case');

ignoreCase.equals('FOO', 'Foo'); // => true
ignoreCase.startsWith('foobar', 'FOO'); // => true
ignoreCase.endsWith('foobar', 'BaR'); // => true
ignoreCase.includes('AbCd', 'c'); // => true
ignoreCase.indexOf('AbCd', 'c'); // => 2
Nick Uraltsev
sumber
12

jika Anda khawatir tentang arah ketidaksetaraan (mungkin Anda ingin menyortir daftar), Anda cukup banyak harus melakukan konversi kasus, dan karena ada lebih banyak karakter huruf kecil di unicode daripada huruf besar keLowerCase mungkin konversi terbaik untuk digunakan.

function my_strcasecmp( a, b ) 
{
    if((a+'').toLowerCase() > (b+'').toLowerCase()) return 1  
    if((a+'').toLowerCase() < (b+'').toLowerCase()) return -1
    return 0
}

Javascript tampaknya menggunakan lokal "C" untuk perbandingan string sehingga urutan yang dihasilkan akan jelek jika string berisi selain huruf ASCII. tidak banyak yang dapat dilakukan tentang itu tanpa melakukan pemeriksaan yang lebih rinci dari string.

Jasen
sumber
7

Misalkan kita ingin mencari variabel string needledalam variabel string haystack. Ada tiga gotcha:

  1. Aplikasi internasional harus menghindari string.toUpperCasedan string.toLowerCase. Gunakan ekspresi reguler yang mengabaikan huruf besar-kecil. Misalnya var needleRegExp = new RegExp(needle, "i");diikuti oleh needleRegExp.test(haystack).
  2. Secara umum, Anda mungkin tidak tahu nilai needle. Hati-hati agar needletidak mengandung ekspresi reguler karakter khusus . Lari ini menggunakan needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");.
  3. Dalam kasus lain, jika Anda ingin mencocokkan secara tepat needledan haystack, hanya mengabaikan huruf besar, pastikan untuk menambahkan "^"di awal dan "$"di akhir konstruktor ekspresi reguler Anda.

Mempertimbangkan poin (1) dan (2), contohnya adalah:

var haystack = "A. BAIL. Of. Hay.";
var needle = "bail.";
var needleRegExp = new RegExp(needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i");
var result = needleRegExp.test(haystack);
if (result) {
    // Your code here
}
Chris Chute
sumber
Anda bertaruh! Yang perlu Anda lakukan adalah mengganti new RegExp(...)bagian dalam baris 3 dengan berikut ini: new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");. Ini memastikan bahwa tidak ada karakter lain sebelum atau setelah string pencarian Anda needle.
Chris Chute
4

Ada dua cara untuk perbandingan kasus sensitif:

  1. Konversikan string ke huruf besar dan kemudian bandingkan dengan menggunakan operator ketat ( ===). Cara ketat operator memperlakukan operan membaca hal-hal di: http://www.thesstech.com/javascript/relational-logical-operators
  2. Pencocokan pola menggunakan metode string:

Gunakan metode string "pencarian" untuk pencarian case-sensitive. Baca tentang pencarian dan metode string lainnya di: http://www.thesstech.com/pattern-matching-using-string-methods

<!doctype html>
  <html>
    <head>
      <script>

        // 1st way

        var a = "apple";
        var b = "APPLE";  
        if (a.toUpperCase() === b.toUpperCase()) {
          alert("equal");
        }

        //2nd way

        var a = " Null and void";
        document.write(a.search(/null/i)); 

      </script>
    </head>
</html>
Sohail Arif
sumber
4

Banyak jawaban di sini, tapi saya ingin menambahkan solusi berdasarkan memperpanjang lib String:

String.prototype.equalIgnoreCase = function(str)
{
    return (str != null 
            && typeof str === 'string'
            && this.toUpperCase() === str.toUpperCase());
}

Dengan cara ini Anda bisa menggunakannya seperti yang Anda lakukan di Jawa!

Contoh:

var a = "hello";
var b = "HeLLo";
var c = "world";

if (a.equalIgnoreCase(b)) {
    document.write("a == b");
}
if (a.equalIgnoreCase(c)) {
    document.write("a == c");
}
if (!b.equalIgnoreCase(c)) {
    document.write("b != c");
}

Output akan menjadi:

"a == b"
"b != c"

String.prototype.equalIgnoreCase = function(str) {
  return (str != null &&
    typeof str === 'string' &&
    this.toUpperCase() === str.toUpperCase());
}


var a = "hello";
var b = "HeLLo";
var c = "world";

if (a.equalIgnoreCase(b)) {
  document.write("a == b");
  document.write("<br>");
}
if (a.equalIgnoreCase(c)) {
  document.write("a == c");
}
if (!b.equalIgnoreCase(c)) {
  document.write("b != c");
}

Nebulosar
sumber
4

Gunakan RegEx untuk pencocokan string atau perbandingan.

Dalam JavaScript, Anda dapat menggunakan match()untuk perbandingan string, jangan lupa untuk memasukkan iRegEx.

Contoh:

var matchString = "Test";
if (matchString.match(/test/i)) {
  alert('String matched');
}
else {
 alert('String not matched');
}
Om Sharma
sumber
1
Pastikan Anda baik-baik saja dengan kecocokan sebagian, jika tidak matchString.match(/^test$/i).
hackel
Apa yang lebih baik daripada "tes" huruf kecil yang Anda miliki var x = 'tes', apakah akan matchString.match(/x/i)berfungsi? Jika tidak, apa yang akan berhasil?
Razvan Zamfir
3
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}
Parth Raval
sumber
3

Jika kedua string memiliki lokal yang sama, Anda mungkin ingin menggunakan Intl.Collatorobjek seperti ini:

function equalIgnoreCase(s1: string, s2: string) {
    return new Intl.Collator("en-US", { sensitivity: "base" }).compare(s1, s2) === 0;
}

Jelas, Anda mungkin ingin melakukan cache Collatoruntuk efisiensi yang lebih baik.

Keuntungan dari pendekatan ini adalah bahwa ia harus jauh lebih cepat daripada menggunakan RegExps dan didasarkan pada seperangkat kolektor siap pakai yang digunakan (lihat deskripsi localesdan optionsparameter konstruktor dalam artikel di atas).

Alexander Abakumov
sumber
Pilihan lain untuk sensitivitas adalah accent, yang membuatnya tidak sensitif, tetapi memperlakukan adan ásebagai karakter yang terpisah. Jadi baseatau accentkeduanya bisa sesuai tergantung pada kebutuhan yang tepat.
Matthew Crumley
2

Saya menulis ekstensi. sangat sepele

if (typeof String.prototype.isEqual!= 'function') {
    String.prototype.isEqual = function (str){
        return this.toUpperCase()==str.toUpperCase();
     };
}
Jhankar Mahbub
sumber
1
Apa yang terjadi dua basis kode dengan ide berbeda tentang bagaimana String # isEqual seharusnya berfungsi mencoba ada pada saat yang sama?
Ryan Cavanaugh
3
@KhanSharp Banyak orang menganggap ini sebagai anti-pola untuk memodifikasi prototipe tipe bawaan. Inilah sebabnya mengapa orang mungkin memilih voting jawaban Anda.
jt000
1
Bukankah lebih buruk memilih definisi metode yang tidak dikenal? Misalnya segera setelah beberapa browser memutuskan untuk menerapkan String#isEqualatau Object#isEqualsecara alami semua halaman Anda berperilaku berbeda dan mungkin melakukan hal-hal aneh jika spesifikasinya tidak cocok dengan Anda.
Robert
2

Bahkan pertanyaan ini sudah dijawab. Saya memiliki pendekatan berbeda untuk menggunakan RegExp dan mencocokkan untuk mengabaikan case sensitif. Silakan lihat tautan saya https://jsfiddle.net/marchdave/7v8bd7dq/27/

$("#btnGuess").click(guessWord);

  function guessWord() {

   var letter = $("#guessLetter").val();
   var word = 'ABC';
   var pattern = RegExp(letter, 'gi'); // pattern: /a/gi

   var result = word.match(pattern);
   alert('Ignore case sensitive:' + result);

  }
David S Lee
sumber
1

Bagaimana kalau TIDAK melempar pengecualian dan TIDAK menggunakan regex lambat?

return str1 != null && str2 != null 
    && typeof str1 === 'string' && typeof str2 === 'string'
    && str1.toUpperCase() === str2.toUpperCase();

Cuplikan di atas menganggap Anda tidak ingin mencocokkan jika string tersebut nol atau tidak terdefinisi.

Jika Anda ingin mencocokkan null / tidak terdefinisi, maka:

return (str1 == null && str2 == null)
    || (str1 != null && str2 != null 
        && typeof str1 === 'string' && typeof str2 === 'string'
        && str1.toUpperCase() === str2.toUpperCase());

Jika karena alasan tertentu Anda peduli tentang undefined vs null:

return (str1 === undefined && str2 === undefined)
    || (str1 === null && str2 === null)
    || (str1 != null && str2 != null 
        && typeof str1 === 'string' && typeof str2 === 'string'
        && str1.toUpperCase() === str2.toUpperCase());
Ben Wilde
sumber
Atau sekadarstr1 == str2 || ...
SLaks
1

Karena tidak ada jawaban yang dengan jelas memberikan cuplikan kode sederhana untuk digunakan RegExp, inilah upaya saya:

function compareInsensitive(str1, str2){ 
  return typeof str1 === 'string' && 
    typeof str2 === 'string' && 
    new RegExp("^" + str1.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "$", "i").test(str2);
}

Ini memiliki beberapa keunggulan:

  1. Memverifikasi jenis parameter (parameter non-string, seperti undefinedmisalnya, akan menabrak ekspresi sepertistr1.toUpperCase() ).
  2. Tidak menderita kemungkinan masalah internasionalisasi.
  3. Melepaskan RegExpstring.
Ohad Schneider
sumber
Tetapi menderita karena kurangnya regexp melarikan diri.
Qwertiy
@Qwertiy fair point, ditambahkan lolos per stackoverflow.com/a/3561711/67824 .
Ohad Schneider
0

Ini adalah versi perbaikan dari jawaban ini .

String.equal = function (s1, s2, ignoreCase, useLocale) {
    if (s1 == null || s2 == null)
        return false;

    if (!ignoreCase) {
        if (s1.length !== s2.length)
            return false;

        return s1 === s2;
    }

    if (useLocale) {
        if (useLocale.length)
            return s1.toLocaleLowerCase(useLocale) === s2.toLocaleLowerCase(useLocale)
        else
            return s1.toLocaleLowerCase() === s2.toLocaleLowerCase()
    }
    else {
        if (s1.length !== s2.length)
            return false;

        return s1.toLowerCase() === s2.toLowerCase();
    }
}



Penggunaan & tes:

Sergey
sumber
0

Ubah keduanya menjadi lebih rendah (hanya sekali untuk alasan kinerja) dan bandingkan dengan operator ternary dalam satu baris:

function strcasecmp(s1,s2){
    s1=(s1+'').toLowerCase();
    s2=(s2+'').toLowerCase();
    return s1>s2?1:(s1<s2?-1:0);
}
Luca C.
sumber
Siapa bilang C sudah mati? : D
Seth
0

Jika Anda tahu Anda berurusan dengan asciiteks maka Anda bisa menggunakan perbandingan offset huruf besar / kecil.

Pastikan string Anda "sempurna" (yang ingin Anda cocokkan) adalah huruf kecil:

const CHARS_IN_BETWEEN = 32;
const LAST_UPPERCASE_CHAR = 90; // Z
function strMatchesIgnoreCase(lowercaseMatch, value) {
    let i = 0, matches = lowercaseMatch.length === value.length;
    while (matches && i < lowercaseMatch.length) {
        const a = lowercaseMatch.charCodeAt(i);
        const A = a - CHARS_IN_BETWEEN;
        const b = value.charCodeAt(i);
        const B = b + ((b > LAST_UPPERCASE_CHAR) ? -CHARS_IN_BETWEEN : CHARS_IN_BETWEEN);
        matches = a === b // lowerA === b
            || A === b // upperA == b
            || a === B // lowerA == ~b
            || A === B; // upperA == ~b
        i++;
    }
    return matches;
}
matsko
sumber
0

Saya suka variasi tulisan cepat ini -

export const equalsIgnoreCase = (str1, str2) => {
    return (!str1 && !str2) || (str1 && str2 && str1.toUpperCase() == str2.toUpperCase())
}

Cepat dalam pemrosesan, dan melakukan apa yang dimaksudkan.

Neetesh Dadwariya
sumber
0

javascriptPerpustakaan ini tampaknya menyediakan banyak operasi string. Sangat nyaman digunakan

Bagaimana cara meng-install

npm install --save string

Impor

var S = require('string');

Abaikan Bandingkan String

var isEqual = S('ignoreCase').equalsIgnoreCase('IGNORECASE')
akash
sumber