JavaScript中比较字符串的最佳方法是什么?

517

我正在尝试优化一个在JavaScript中进行字符串二分查找的函数。

二分查找需要知道关键字==<中间值。

但是这要求在JavaScript中进行两次字符串比较,不像类似于C语言中有strcmp()函数,它返回三个值(-1, 0, +1)表示(小于、等于、大于)。

是否有一种原生的JavaScript函数,可以返回三元值,从而在二分搜索的每次迭代中只需要进行一次比较?


13
return str1 < str2 ? -1 : str1 > str2; 的翻译是:如果 str1 小于 str2,则返回-1,否则返回 str1 是否大于 str2。 - 1''
6
不太理想,需要进行两次字符串比较。 - HRJ
4
在我的机器上,它仍然比“localeCompare()”快一个数量级!@Gumbo的定制“strcmp()”可能会更快,这取决于字符串相等比较的内部实现有多么优化。 - 1''
4
无论如何,您需要进行两个比较!一个是用于查看是否 a > b,另一个是用于检查它们是否相等。JavaScript 对于确定字符串是否相等非常快,因为如果它们相等,则它们是同一对象。这就像比较两个指针一样,字符串被“原子化”并存储在哈希表中,因此对于每组字母的组合,只存在一个实例。 - Pizzaiola Gorgonzola
2
我建议重新打开这个问题,而不是参考关于strcmp的问题,即使那个问题的答案是相同的,因为我认为并不是所有寻找答案的人都知道strcmp - Dan Nissenbaum
显示剩余5条评论
3个回答

688

14
很遗憾,stringCompare不可靠。 Opera、IE、Firefox、Chrome和Safari都会对'dog'.localeCompare('cat')返回1,这是可以预料的,当你反转调用者和参数时则返回-1。但是大写字母的行为表现很奇怪—— 'dog'.localeCompare('Dog')在我测试的浏览器中,只有Safari 4返回1。 在IE8和Firefox 3中返回-1, 而Opera 9和Chrome则都返回+32。 - kennebec
33
当您想进行不区分大小写的比较时,可以使用toLowerCase或toLocaleLowerCase。 - Fabrice
2
我认为需要注意的是,V8(Chrome) 在解释ECMA-262时与IE/Firefox在localeCompare上有所不同。例如: "a".localeCompare("Z")应该返回-1,但实际上返回7,这是"a"- "Z"的charcode。不幸的是,规范中的语言很散漫,只指定localeCompare()返回负数、正数或0。(没有具体的-1、1、0)。我已经提交了一个错误报告,希望这个问题能够改变,但自2010年8月以来一直存在,所以我怀疑它会不会改变。 - JoshVarty
10
看来你最好自己比较一下;http://jsperf.com/localecompare - Gerben Jacobs
2
@GerbenJacobs 感谢您的回复。我也从中推导出了一个更大的基准测试(二分查找):http://jsperf.com/localecompare/2 - HRJ
显示剩余9条评论

82

在JavaScript中,您可以将两个字符串的值与整数进行比较,因此可以这样做:

  • "A" < "B"
  • "A" == "B"
  • "A" > "B"

因此,您可以创建自己的函数,以与 strcmp() 相同的方式检查字符串。

以下是执行相同操作的函数:

function strcmp(a, b)
{   
    return (a<b?-1:(a>b?1:0));  
}

16
请再次阅读原始问题!关键是要避免进行多个字符串比较。 - Pointy
19
抱歉,我没看到那个……至少对某些人来说这个有用。=| - Cipi

15
你可以使用比较运算符比较字符串。一个strcmp函数可以定义为这样:
function strcmp(a, b) {
    if (a.toString() < b.toString()) return -1;
    if (a.toString() > b.toString()) return 1;
    return 0;
}

编辑 这里是一个字符串比较函数,最多只需要进行 min { length(a), length(b) } 次比较就可以确定两个字符串之间的关系:

function strcmp(a, b) {
    a = a.toString(), b = b.toString();
    for (var i=0,n=Math.max(a.length, b.length); i<n && a.charAt(i) === b.charAt(i); ++i);
    if (i === n) return 0;
    return a.charAt(i) > b.charAt(i) ? -1 : 1;
}

12
但是这个例程恰恰做了 OP 不想做的事情:它进行了两次字符串比较(更不用说那些对 "toString" 函数的调用了)。 - Pointy
1
@Pointy:仅通过一次比较是不可能的。您需要至少进行min {a.length, b.length}步骤(每次比较两个字符)才能确定字符串是否相等。(即使是localeCompare也会在内部执行此操作。) - Gumbo
2
不,localeCompare 不会在内部执行此操作。比较字符是通过减法实现的,因此一旦该操作产生非零结果,您就知道答案了。您的答案可以重新比较每个字符串的可能 所有 字符。 - Pointy
@Gumbo localeCompare不一定非得在Javascript中实现,它也可以本地化实现。或者我漏掉了什么... - HRJ
也许我漏掉了什么。当您编写两个完全独立的JavaScript字符串比较时,会发生什么?好吧,第一个比较开始了(假设)并且它注意到字符位置5处不匹配。也就是说,第1到4个字符匹配,但第5个字符不匹配。如果第一个JavaScript比较是“!=”比较(或“==”;无论哪种),那么我们知道这些字符串不相等。然而,在低级别的比较代码中,我们还知道“<”和“>”的答案。但是,当我们开始下一个(JavaScript)比较并重新比较字符1-4时,我们放弃了那些知识。 - Pointy
显示剩余3条评论

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