如何进行不区分大小写的字符串比较?

如何在JavaScript中执行不区分大小写的字符串比较?

1149523 次浏览

最简单的方法(如果你不担心特殊的Unicode字符)是调用toUpperCase

var areEqual = string1.toUpperCase() === string2.toUpperCase();

编辑:这个答案最初是在9年前添加的。今天你应该使用#0sensitivity: '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 detectionreturn ciEqualsInner('A', 'a')? ciEqualsInner(a, b): /*  fallback approach here  */;}

原答复

在JavaScript中进行不区分大小写比较的最佳方法是使用带有i标志的RegExpmatch()方法。

不区分大小写的搜索

当被比较的两个字符串都是变量(不是常量)时,那么它就有点复杂了,因为你需要从字符串中生成一个RegExp,但是如果字符串中有特殊的正则表达式字符,则将字符串传递给RegExp构造函数可能会导致不正确的匹配或失败的匹配。

如果您关心国际化,请不要使用toLowerCase()toUpperCase(),因为它不能在所有语言中提供准确的不区分大小写的比较。

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

我写了一个扩展非常琐碎

if (typeof String.prototype.isEqual!= 'function') {String.prototype.isEqual = function (str){return this.toUpperCase()==str.toUpperCase();};}

更新时间:

根据评论,前面的答案检查source contains keyword,使其平等检查添加^$

(/^keyword$/i).test(source)

在正则表达式的帮助下,我们也可以实现。

(/keyword/i).test(source)

/i用于忽略大小写。如果没有必要,我们可以忽略并测试不区分大小写的匹配,例如

(/keyword/).test(source)

请记住,大小写是一个特定于语言环境的操作。根据场景,你可能需要考虑到这一点。例如,如果你正在比较两个人的名字,你可能想考虑语言环境,但如果你正在比较机器生成的值,如UUID,那么你可能不会。这就是为什么我在我的utils库中使用以下函数(请注意,出于性能原因,不包括类型检查)。

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

如果你关心不等式的方向(也许你想排序一个列表)您几乎必须进行大小写转换,并且由于Unicode中的小写字符比大写字符更多,因此LowerCase可能是最好的转换使用。

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

Javascript似乎使用语言环境“C”进行字符串比较,因此结果的排序将如果字符串包含除ASCII字符以外的其他字符,则是丑陋的。如果不对字符串进行更详细的检查,则无法做到这一点。

不区分大小写的比较有两种方法:

  1. 将字符串转换为大写,然后使用严格运算符(===)进行比较。
  2. 使用字符串方法进行模式匹配:

使用“search”字符串方法进行不区分大小写的搜索。

<!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>

甚至这个问题已经回答了。我有一种不同的方法来使用RegExp和Match来忽略大小写敏感性。请查看我的链接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);}

我最近创建了一个微型库,它提供了不区分大小写的字符串助手:https://github.com/nickuraltsev/ignore-case。(它在内部使用toUpperCase。)

var ignoreCase = require('ignore-case');
ignoreCase.equals('FOO', 'Foo'); // => trueignoreCase.startsWith('foobar', 'FOO'); // => trueignoreCase.endsWith('foobar', 'BaR'); // => trueignoreCase.includes('AbCd', 'c'); // => trueignoreCase.indexOf('AbCd', 'c'); // => 2

假设我们想在字符串变量haystack中找到字符串变量needle。有三个陷阱:

  1. 国际化应用程序应避免string.toUpperCasestring.toLowerCase。使用忽略大小写的正则表达式。例如,var needleRegExp = new RegExp(needle, "i");后跟needleRegExp.test(haystack)
  2. 一般来说,您可能不知道needle的值。请注意needle不包含任何正则表达式特殊字符。使用needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");转义这些。
  3. 在其他情况下,如果您想精确匹配needlehaystack,只需忽略大小写,请确保在正则表达式构造函数的开头添加"^",在末尾添加"$"

考虑到(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}

如何不抛出异常和不使用慢正则表达式?

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

上面的代码段假设您不想匹配字符串是否为null或未定义。

如果你想匹配null/unset,那么:

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

如果由于某种原因,你关心未定义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());
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');if (regex.test(str)) {console.log("true");}

这里有很多答案,但我喜欢添加一个基于扩展String lib的解决方案:

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

由于没有答案清楚地提供了使用RegExp的简单代码片段,这是我的尝试:

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

它有几个优点:

  1. 验证参数类型(任何非字符串参数,例如undefined,都会使像str1.toUpperCase()这样的表达式崩溃)。
  2. 不存在可能的国际化问题。
  3. 转义RegExp字符串。

使用RegEx进行字符串匹配或比较。

在JavaScript中,您可以使用match()进行字符串比较,不要忘记在RegEx中输入i

示例:

var matchString = "Test";if (matchString.match(/test/i)) {alert('String matched');}else {alert('String not matched');}

如果两个字符串都属于相同的已知语言环境,您可能希望使用#0对象,如下所示:

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

显然,您可能希望缓存Collator以提高效率。

这种方法的优点是,它应该比使用RegExps快得多,并且基于非常可定制的(请参阅上面文章中对localesoptions构造函数参数的描述)即用型排序器集。

正如最近的评论所说,#0支持不区分大小写的比较(以及其他强大的功能)。

这里有一个简单的例子

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

还有一个你可以使用的通用函数

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

请注意,您可能应该输入您正在使用的特定语言环境,而不是undefined。这很重要,如MDN文档所示

在瑞典语中,ä和a是独立的基本字母

灵敏度选项

从MDN列表的敏感性选项

浏览器支持

截至发帖时,适用于Android和Opera Mini的UC浏览器不要支持区域设置选项参数。请检查https://caniuse.com/#search=localeCompare以获取最新信息。

这是这个答案改进版本

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)elsereturn s1.toLocaleLowerCase() === s2.toLocaleLowerCase()}else {if (s1.length !== s2.length)return false;
return s1.toLowerCase() === s2.toLowerCase();}}



用法和测试:

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)elsereturn s1.toLocaleLowerCase() === s2.toLocaleLowerCase()}else {if (s1.length !== s2.length)return false;
return s1.toLowerCase() === s2.toLowerCase();}}
// If you don't mind extending the prototype.String.prototype.equal = function(string2, ignoreCase, useLocale) {return String.equal(this.valueOf(), string2, ignoreCase, useLocale);}
// ------------------ TESTS ----------------------console.log("Tests...");
console.log('Case sensitive 1');var result = "Abc123".equal("Abc123");console.assert(result === true);
console.log('Case sensitive 2');result = "aBC123".equal("Abc123");console.assert(result === false);
console.log('Ignore case');result = "AbC123".equal("aBc123", true);console.assert(result === true);
console.log('Ignore case + Current locale');result = "AbC123".equal("aBc123", true);console.assert(result === true);
console.log('Turkish test 1 (ignore case, en-US)');result = "IiiI".equal("ıiİI", true, "en-US");console.assert(result === false);
console.log('Turkish test 2 (ignore case, tr-TR)');result = "IiiI".equal("ıiİI", true, "tr-TR");console.assert(result === true);
console.log('Turkish test 3 (case sensitive, tr-TR)');result = "IiiI".equal("ıiİI", false, "tr-TR");console.assert(result === false);
console.log('null-test-1');result = "AAA".equal(null);console.assert(result === false);
console.log('null-test-2');result = String.equal(null, "BBB");console.assert(result === false);
console.log('null-test-3');result = String.equal(null, null);console.assert(result === false);

将两者都转换为较低的字符串(出于性能原因仅一次)并将它们与内联三元运算符进行比较:

function strcasecmp(s1,s2){s1=(s1+'').toLowerCase();s2=(s2+'').toLowerCase();return s1>s2?1:(s1<s2?-1:0);}

如果您知道您正在处理ascii文本,那么您可以使用大写/小写字符偏移比较。

只需确保您的“完美”字符串(您要匹配的字符串)是小写的:

const CHARS_IN_BETWEEN = 32;const LAST_UPPERCASE_CHAR = 90; // Zfunction 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 == ~bi++;}return matches;}

我喜欢这种速记变化-

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

快速处理,并做它打算做的事情。

为了更好的浏览器兼容性,您可以依赖正则表达式。这将适用于过去20年中发布的所有Web浏览器:

String.prototype.equalsci = function(s) {var regexp = RegExp("^"+this.replace(/[.\\+*?\[\^\]$(){}=!<>|:-]/g, "\\$&")+"$", "i");return regexp.test(s);}
"PERSON@Ü.EXAMPLE.COM".equalsci("person@ü.example.com")// returns true

这与此处找到的其他答案不同,因为它考虑到并非所有用户都在使用现代Web浏览器。

注意:如果您需要支持像土耳其语这样的异常情况,您需要使用localeCompare,因为i和I在土耳其语中不是同一个字母。

"I".localeCompare("i", undefined, { sensitivity:"accent"})===0// returns true"I".localeCompare("i", "tr", { sensitivity:"accent"})===0// returns false

我们也可以使用ASCII:

function toLower(a){
let c = "";
    
for(let i = 0;i<a.length;i++){
        
let f = a.charCodeAt(i);if(f < 95){
c += String.fromCharCode(f+32);}else{
c += a[i];}}
return c;}function compareIt(a,b){

return toLower(a)==toLower(b);

}console.log(compareIt("An ExamPlE" , "an example"));