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

1436

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


43
请查看新添加的 .localeCompare() JavaScript 方法。目前仅有现代浏览器支持(IE11+)。请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare 。 - Adriano
7
在Chrome 48控制台中,"A".localeCompare( "a" )返回值为1。 - manuell
1
@manuell 如果您传递 { sensitivity: 'accent' }{ sensitivity: 'base' } 选项,则 localeCompare 将执行不区分大小写的比较。 "A".localeCompare("a", undefined, { sensitivity: 'accent' }) === 0 - JLRishe
23个回答

1505

编辑:此答案最初是在10年前添加的。今天应该使用localeCompare。请参见其他答案。

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

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

61
在所有语言中,将文本转换为大写或小写可以提供正确的不区分大小写比较。http://www.i18nguy.com/unicode/turkish-i18n.html - Samuel Neff
67
我知道。这就是为什么我写了“如果您不担心特殊Unicode字符”的原因。 - SLaks
198
相比于 toLowerCase,有理由更喜欢使用 toUpperCase 吗? - jpmc26
175
好的,我会尽力进行翻译。以下是需要翻译的内容:@jpmc26: Yes; http://msdn.microsoft.com/en-us/library/bb386042.aspx 和 http://en.wikipedia.org/wiki/Capital_%E1%BA%9E - SLaks
15
这个回答已经有9年了,现在有新的功能,所以根据你评论的日期来看,不,它不是JS最好的选择。请参考下面有关 localeCompare 的更新更近的答案(但仍然是5年前)。我不知道过去五年里是否有任何变化使 localeCompare 不再是最好的答案。 - Samuel Neff
显示剩余5条评论

354

编辑:这个回答最初是在9年前添加的。今天您应该使用localeComparesensitivity: '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中执行不区分大小写的比较的最佳方法是使用RegExp match()方法及i标志。

不区分大小写搜索

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

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

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


5
@Quandary,是的,这就是我说过必须处理的问题 - “你需要从字符串生成一个RegExp,但是如果字符串中有特殊的正则表达式字符,通过将字符串传递给RegExp构造函数可能会导致匹配不正确或匹配失败。” - Samuel Neff
30
使用这种方法进行不区分大小写的字符串比较是最昂贵的解决方案。RegExp适用于复杂的模式匹配,因此需要为每个模式构建一个决策树,然后对输入字符串执行该决策树。虽然它可以工作,但相当于乘坐喷气式飞机去下一个街区购物。 简而言之,请不要这样做。 - Agoston Horvath
2
我可以使用localeCompare(),但是对于'a'.localeCompare('A')它返回-1,就像OP一样,我正在寻找不区分大小写的字符串比较。 - StingyJack
6
要使用localeCompare进行不区分大小写的比较,可以尝试使用以下代码:'a'.localeCompare('A', undefined, { sensitivity: 'base' }) - Judah Gabriel Himango
2
注意:localeCompare 版本要求 JavaScript 引擎支持 ECMAScript® 国际化 API,但这并非必须。因此,在依赖它之前,您可能需要检查它在您使用的环境中是否可用。例如:const compareInsensitive = "x".localeCompare("X", undefined, {sensitivity: "base"}) === 0 ? (a, b) => a.localeCompare(b, undefined, {sensitivity: "base"}) : (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()); 或类似的内容。 - T.J. Crowder
显示剩余3条评论

158

如最近的评论所说,string::localeCompare 支持大小写不敏感比较(以及其他强大的功能)。

这是一个简单的例子:

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

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

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

请注意,不要使用undefined,而应该输入您正在使用的具体语言环境。正如MDN文档所示,这非常重要。

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

敏感度选项

Sensitivity options tabulated from MDN

浏览器支持

截至发布时,安卓UC浏览器和Opera Mini不支持localeoptions参数。请查看https://caniuse.com/#search=localeCompare以获取最新信息。


1
我相当确定浏览器不会定期从旧版本中删除功能支持,这里列出的浏览器支持是不正确或至少不完整的(根据您的caniuse链接)。 IE <11,Firefox <29,Chrome <24和Safari <10(仅列出流行的浏览器)也不支持“locale”和“options”参数,并且在发布此答案时很可能也不支持。对于新读者来说,这可能比列出基本上不支持任何现代功能的晦涩浏览器更有用。 - M.Babcock

53

更新:

根据评论,之前的答案检查了source包含关键字,为了进行等值检查,添加了^$

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

借助正则表达式,我们也可以实现。

(/keyword/i).test(source)

/i 是忽略大小写的。如果不需要,我们可以忽略并测试不区分大小写的匹配方式,如:

(/keyword/).test(source)

19
使用这样的正则表达式将匹配子字符串!在您的示例中,字符串 keyWORD 将确实导致正匹配。但是字符串 this is a keyword yokeywords 也将导致正匹配。请注意 :) - Elmer
7
这并没有回答问题中所问的“相等性”检查(不区分大小写)!但这是一个“包含性”检查!不要使用它。 - S.Serpooshan
7
当然,为了匹配整个字符串,正则表达式可以改为/^keyword$/.test(source),但是,1)如果keyword不是一个恒定的值,你需要执行 new RegExp('^' + x +'$')。test(source);2)使用正则表达式来测试如此简单的不区分大小写的字符串相等性并不高效。 - JHH
const regexpEqual = (a, b) => (new RegExp(^${a}$, "gi")).test(b) - Sam Hasler

34

请记住,大小写转换是与语言环境相关的操作。根据情况,您可能需要考虑这一点。例如,如果您要比较两个人的姓名,则可能要考虑语言环境,但如果您要比较机器生成的值,例如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;
}

1
你使用 "!!" 进行显式布尔转换的原因是什么,而不是允许 if 语句评估值的真实性? - Celos
不是必需的。我想这是从我其他更复杂的代码版本中得到的。我已经更新了答案。 - Shital Shah
@thekodester,你的函数有一个bug。这个compareStrings("", "")会返回false,尽管这两个字符串是相等的。 - Serg
@Sergey 我尝试过了,我的返回结果是“true”。也许这是你的浏览器出现了问题? - Jenna Sloan
地区设置绝对是需要考虑的重要因素。+1 - PHP Guru

14
如果您担心不平等的方向(也许您想对列表进行排序),则您几乎必须执行大小写转换。由于 Unicode 中的小写字符比大写字符多,因此 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字母以外的内容,则结果排序将变得不美观。除非对字符串进行更详细的检查,否则不太可能解决这个问题。


13

我最近创建了一个微型库,提供了不区分大小写的字符串助手: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

8

使用正则表达式进行字符串匹配或比较。

在JavaScript中,您可以使用match()进行字符串比较, 不要忘记在正则表达式中加上i。此标志将强制执行不区分大小写的测试。

示例:

确认任何情况下的字符串test是否包含在matchString变量的任何位置中

var matchString = "Test";
if (matchString.match(/test/i)) {
    alert('matchString contains the substring "test" case insensitive');
}
else {
    alert('matchString does not contain the substring "test" case insensitive');
}

要确认matchString变量只包含任何大小写的test,且没有其他字符,则使用正则表达式中的零宽断言^$。这些将要求test直接出现在字符串开头之后和字符串结尾之前。

var matchString = "Test";
if (matchString.match(/^test$/i)) {
    alert('matchString equals "test" case insensitive');
}
else {
    alert('matchString does not equal "test" case insensitive');
}

3
请确保您可以接受部分匹配,否则使用 matchString.match(/^test$/i) - hackel
如果不是小写的 "test",而是使用变量 var x = 'test',那么 matchString.match(/x/i) 能起作用吗?如果不能,应该如何操作? - Razvan Zamfir
@RazvanZamfir ,如果是动态模式,您可以使用RegExp对象 例如:var x = new RegExp(/test/, "gi"); matchString.match(x); - Om Prakash Sharma
或者 const x_regex = new RegExp(`^${x}$`, "gi");,不过有点乱。 - user4945014
正则表达式性能差 - serge
显示剩余2条评论

7
很多答案都在这里,但我想添加一个基于扩展字符串库的解决方案:
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");
}


这是最聪明的解决方案,为您打开了许多其他操作的大门,这些操作可能在语言中缺失。 - Ro Yo Mi

7
假设我们想在字符串变量 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
}

没问题!你只需要将第3行中的new RegExp(...)部分替换为以下内容:new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");。这样可以确保在你的搜索字符串needle之前或之后没有其他字符。 - Chris Chute

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