Вопрос по string, javascript – Сравнение строк без учета регистра в JavaScript

838

Как выполнить сравнение строк без учета регистра в JavaScript?

@AdrienBe"A".localeCompare( "a" ); возвращается1 в консоли Chrome 48. manuell
@manuelllocaleCompare делает сравнение без учета регистра, если вы передаете{ sensitivity: 'accent' } или же{ sensitivity: 'base' } вариант. ,"A".localeCompare("a", undefined, { sensitivity: 'accent' }) === 0 JLRishe
Потому что сравнение, как я полагаю, часто используется для сортировки / упорядочивания строк. Я прокомментировал здесь давным-давно.=== проверим на равенство, но выигралне достаточно хорош для сортировки / упорядочивания строк (см. вопрос, на который я изначально ссылался). Adrien Be
смотрите такжеstackoverflow.com/questions/51165/... Adrien Be

Ваш Ответ

12   ответов
130

РЕДАКТИРОВАТЬ: Этот ответ был первоначально добавлен 9 лет назад. Сегодня вы должны использоватьlocaleCompare сsensitivity: 'accent' опция:

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

{ sensitivity: 'accent' } говоритlocaleCompare() рассматривать два варианта одной и той же базовой буквы как одинаковыеесли у них разные акценты (как в третьем примере) выше.

Кроме того, вы можете использовать{ sensitivity: 'base' }, который обрабатывает два символа как эквивалентные, если их базовый символ одинаков (такA будет рассматриваться как эквивалентá).

Заметка что третий параметрlocaleCompare не поддерживается в IE10 или более ранних версиях или некоторых мобильных браузерах (см. таблицу совместимости на странице, указанной выше), поэтому, если вам требуется поддержка этих браузеров, вы 'понадобится какой-нибудь запасной вариант:

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  */;
}

Оригинальный ответ

Лучший способ сделать сравнение без учета регистра в JavaScript - это использовать RegExpmatch() метод сi флаг.

Поиск без учета регистра

Когда обе сравниваемые строки являются переменными (не константами), тогданемного сложнеепотому что вам нужно сгенерировать RegExp из строки, но передача строки в конструктор RegExp может привести к неправильным совпадениям или неудачным совпадениям, если в строке есть специальные символы регулярного выражения.

Если вы заботитесь о интернационализации, нет использоватьtoLowerCase() или жеtoUpperCase() как это не• обеспечить точное сравнение без учета регистра на всех языках.

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

@RLRishe спасибо за редактирование. Отличное дополнение. Я'Я удивлен, что вы бы порекомендовали чувствительностьaccent и неbase? Для сравнения нетне принято ли игнорировать акценты, так как при вводе данных для поиска люди часто их пропускают? Я понимаю, что это полностью зависит от контекста, просто любопытно, что обычно более распространено. Samuel Neff
@SamuelNeff Я полагаю, что для какой-то функции поиска вы, вероятно, захотите игнорировать акценты, но для простого сравнения двух значений без учета регистра я бы хотел принять во внимание акценты, потому что, например, «añОперационные системы" а также "Anos» два совершенно разных слова. Я'Я не уверен, что является более распространенным, и яЯ думаю, это зависит от ситуации. То есть's проблема некоторых языков, которые пропускают акценты на заглавных буквах, так чтонемного гадости. FWIW, .NET 'Встроенное сравнение без учета регистра рассматривает акценты как существенные. JLRishe
Использование этого является наиболее дорогостоящим решением для сравнения строк без учета регистра. RegExp предназначен для сложного сопоставления с шаблоном, поэтому он должен построить дерево решений для каждого шаблона, а затем выполнить его для входных строк. В то время как это будет работать, это сравнимо с поездкой на реактивном самолете за покупками в следующем квартале. д-р, пожалуйста, несделать это Agoston Horvath
я мог бы использовать localeCompare (), но его возвращение -1 для'a'.localeCompare('A') и как опера яищу строку без учета регистра. I ' StingyJack
10

если вас беспокоит направление неравенства (возможно, вы хотите отсортировать список), вам, скорее всего, нужно выполнить преобразование регистра, и, поскольку в юникоде больше строчных символов, чем заглавных, toLowerCase, вероятно, является лучшим преобразованием для использования.

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

Javascript, кажется, использует локаль "C" для сравнения строк, поэтому результирующее упорядочение будет некрасивым, если строки содержат не буквы ASCII. там'с этим мало что можно сделать, не проводя гораздо более детального осмотра строк.

959

Самый простой способ сделать это (если выне беспокоиться о специальных символов Unicode) это позвонить:toUpperCase

var areEqual = string1.toUpperCase() === string2.toUpperCase();
Это гений! naspy971
Для JavaScript этот ответ кажется неправильным, "ß".toUpperCase () приводит к "SS»поэтому делает сравнение бесполезным. fr34kyn01535
Что вы подразумеваете под "если ты'не беспокоиться о специальных символов Unicode " ? Какое влияние оказывает toUpperCase на эти символы? faressoft
@Nateowami Хорошо, тогда у нас другое поведение в разных браузерных движках. Sven
3
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}
Регулярное выражение должно быть экранировано. Qwertiy
12

Как сказано в последних комментариях,string::localCompare поддерживает сравнение без учета регистра (среди других важных вещей).

Вот'простой пример

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

И универсальная функция, которую вы могли бы использовать

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

Обратите внимание, что вместоundefined вам, вероятно, следует ввести конкретную локаль, с которой вы работаете. Это важно, как указано в документах MDN.

на шведском, ä и являются отдельными базовыми буквами

Варианты чувствительности

Поддержка браузера

На момент публикации UC Browser для Android и Opera Miniне делайте служба поддержкиместо действия а такжеопции параметры. пожалуйста, проверьтеhttps://caniuse.com/#search=localeCompare для актуальной информации.

Связанные с:i18nguy.com/unicode/turkish-i18n.html jay
4

Здесь много ответов, но мне нравится добавлять решение, основанное на расширении библиотеки String:

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

Таким образом, вы можете использовать его так же, как в Java!

Пример:

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

Выход будет:

"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("
"); } if (a.equalIgnoreCase(c)) { document.write("a == c"); } if (!b.equalIgnoreCase(c)) { document.write("b != c"); }

5

Предположим, мы хотим найти строковую переменнуюneedle в строковой переменнойhaystack, Есть три ошибки:

  1. Интернационализированные приложения должны избегатьstring.toUpperCase а такжеstring.toLowerCase, Используйте регулярное выражение, которое игнорирует регистр. Например,var needleRegExp = new RegExp(needle, "i"); с последующим .needleRegExp.test(haystack)
  2. В общем, вы можете не знать значениеneedle, Будьте осторожны, чтоneedle не содержит регулярных выраженийспециальные символы, Побег это, используя.needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  3. В других случаях, если вы хотите точно соответствоватьneedle а такжеhaystack, просто игнорируя регистр, обязательно добавьте"^" в начале и"$" в конце вашего конструктора регулярных выражений.

Принимая во внимание пункты (1) и (2), примером будет:

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
}
Можете ли вы предоставить добавить пример точного соответствия, игнорируя регистр. Вы описываете, как вы это делаете, но если кто-то неЯ не знаю, как разместить ^ и $. HelpMeStackOverflowMyOnlyHope
Вы держите пари! Все, что вам нужно сделать, это заменитьnew RegExp(...) часть в строке 3 со следующим:new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");, Это гарантирует отсутствие других символов до или после строки поиска.needle Chris Chute
11

Недавно я создал микробиблиотеку, которая предоставляет регистронезависимые помощники строк:https://github.com/nickuraltsev/ignore-case, (Оно используетtoUpperCase внутренне.)

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
26

Помните, что оболочка - это операция, специфичная для локали В зависимости от сценария вы можете принять это во внимание. Например, если вы сравниваете имена двух людей, вы можете рассмотреть локаль, но если вы сравниваете сгенерированные машиной значения, такие как UUID, то вы можете этого не делать. Вот почему я использую следующую функцию в моей библиотеке утилит (обратите внимание, что проверка типа не включена по соображениям производительности).

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;
}
Лучше, чем остальные примеры, но все равно выдает нулевую ссылку. Stefan Steiger
Есть ли причина, по которой вы используете!!» выполнить явное логическое преобразование, вместо того чтобы позволить условию if оценивать достоверность значений? Celos
Функция в ответе ведет себя правильно:jsbin.com/bebifehafu/edit?html,output Shital Shah
Это должно быть ответом. Я'реорганизовал @ShitalShah 'Идея и поставить здесь:stackoverflow.com/a/53379742/1844247 Sergey
4

Существует два способа сравнения без учета регистра:

  1. Преобразуйте строки в верхний регистр, а затем сравните их, используя строгий оператор (===). Как строгий оператор относится к операндам, прочитанным в:http://www.thesstech.com/javascript/relational-logical-operators
  2. Сопоставление с шаблоном с использованием строковых методов:

Использовать "поиск" строковый метод для поиска без учета регистра. Читайте о поиске и других строковых методах по адресу:http://www.thesstech.com/pattern-matching-using-string-methods


  
    
      
    

29

С помощью регулярного выражения также мы можем достичь.

(/keyword/i).test(source)

/i для игнорирования дела. Если в этом нет необходимости, мы можем проигнорировать и проверить на НЕ совпадение с учетом регистра, например

(/keyword/).test(source)
Это не отвечаетравенство проверьте (без учета регистра), как указано в вопросе! Но этоСодержит проверять! Дон»не использовать это S.Serpooshan
Конечно, чтобы соответствовать всей строке, регулярное выражение может быть изменено на/^keyword$/.test(source), но 1) еслиkeyword не константа, тынужно сделатьnew RegExp('^' + x + '$').test(source) и 2) использование регулярного выражения для проверки чего-либо столь простого, как равенство строк без учета регистра, совсем не очень эффективно. JHH
Использование такого регулярного выражения будет соответствовать подстрокам! В вашем примере строкаkeyWORD приведет к положительному совпадению. Но строкаthis is a keyword yo или жеkeywords также приведет к положительному совпадению. Помните об этом :-) Elmer
2

Я написал расширение. очень тривиально

if (typeof String.prototype.isEqual!= 'function') {
    String.prototype.isEqual = function (str){
        return this.toUpperCase()==str.toUpperCase();
     };
}
Я думаю, что у Роберта есть правильная точка зрения. Прекрасная идея, но, возможно, соглашение об именах слишком обобщенное или слишком вероятное для использования в будущем спецификацией JavaScript. Может быть, все вы методы расширения могут бытьprototype.ksxIsEqual тогда, если вы захотите найти все свои расширения, у вас будет простой способ сделать это, и он, вероятно, никогда не будет конфликтовать. Eric Bishard
Два не могут существовать одновременно с одним и тем же именем. Если вы добавляете одно самостоятельно, вы можете либо изменить имя, либо проверить, существует ли другое. Если другой существует, вы можете использовать другой внутри своей реализации. Если оба исходят из двух разных библиотек, кто бы ни был последним, он должен работать сам. Если можете дать мне больше деталей, я могу иметь глубокий взгляд. (Мне любопытно, почему за мой ответ проголосовали?) KhanSharp
Многие считают анти-паттерн модифицировать прототип встроенных типов ». Тот'Слишком упрощение. Например, если метод родного прототипа запланирован или уже существует в современных браузерах, он 'S вполне допустимо, чтобы проверить его существование и "переопределение» это если этоее нет, если вы реализуете функцию, так что она ведет себя так же, как и нативная (т.е.регулировочная шайба»). Вы можете'просто посмотриNativeClass.prototype.nativeMethod = " и выкрикни OMG. Настоящая проблема здесь в том, что это неt как будет работать нативная реализация (то есть isEqual будет чувствительна к регистру). Triynko
Isn»Не считается ли предпочтительным определение неизвестного метода? Например, как только какой-то браузер решит реализоватьString#isEqual или жеObject#isEqual изначально все ваши страницы ведут себя по-разному и могут делать странные вещи, если спецификация неТочно соответствует вашему. Robert

Похожие вопросы