JavaScript:搜索字符串时indexOf与Match是否匹配?


69

除了可读性,使用之间是否有任何明显的区别(也许是性能)

str.indexOf("src") 

str.match(/src/)

我个人更喜欢match(和正则表达式),但同事似乎却选择了相反的方式。我们想知道这是否重要...?

编辑:

我应该在一开始就说过,这是针对将进行部分纯字符串匹配(以获取JQuery的类属性中的标识符)的函数,而不是使用通配符等进行全正则表达式搜索的函数。

class='redBorder DisablesGuiClass-2345-2d73-83hf-8293' 

因此,两者之间的区别在于:

string.indexOf('DisablesGuiClass-');

string.match(/DisablesGuiClass-/)

4
我认为str.indexOf("xyz")应该与/xyz/.test(str)
Redu

1
这里是一个基准,它比较indexOf,regex和匹配jsben.ch/#/r9hBp
EscapeNetscape

实际上String.prototype.indexOf更具有可比性,String.prototype.search因为两者都将返回比赛的开始索引。布尔表达式'foo'.indexOf('bar') !== -1的可比性更好,/bar/.test('foo')因为两者都会产生布尔值。就是说,对于没有组和锚的简单表达式,性能应该是可比的。str.match这样做浪费了太多时间,因为它会返回所有匹配项,因此建议不要将其用于比较。也就是说,如果您没有性能问题,请选择可读性更高的一个。
Torsten Walter

Answers:


61

RegExp实际上比indexOf慢(您可以在此处看到它),尽管通常这不是问题。使用RegExp,还必须确保正确地对字符串进行转义,这是需要考虑的额外事情。

除了这两个问题之外,如果两种工具完全能够满足您的需求,为什么不选择简单的工具呢?


对我来说很有意义,因此indexOf除非需要其他RegExp功能,否则我们将继续使用。非常感谢!PS。您在响应中链接到的可配置测试页很酷-是公开可用的东西还是您自己设计的东西?
indra 2011年

3
@ 5arx,jsperf和jsfiddle一样,是用于快速测试想法的必不可少的工具。这是一个公共站点,只需访问jsperf.com并创建自己的测试。
David Tang

10
根据这个jsperf测试,indexOf总是很快是不正确的:stackoverflow.com/a/5296314/981933
F Lekschas

1
您所指的测试可能是正确的,也可能不是,它肯定是RegExp错误的,这没有激发信心。'[\\?|&]'应该[?&]匹配?&-不需要|运算符,也不要转义?
LeeGee'3

仅添加历史颜色:截至本评论发表之日,在我的机器上(2017 MBP,带有Mac OS X 10.12.3上的Chrome 56.0.2924),答案中链接的测试表明indexOf速度慢12%正则表达式匹配。因此,在很多方面,正确的答案可能是:这取决于。
davemyron

19

您的比较可能并不完全公平。indexOf用于纯字符串,因此非常快;match使用正则表达式-当然,相比而言,它可能要慢一些,但是如果要进行正则表达式匹配,您将无法接受indexOf。另一方面,可以优化正则表达式引擎,并且近年来性能一直在提高。

在您的情况下,如果您要查找逐字字符串,indexOf就足够了。但是,对于正则表达式仍然有一个应用程序:如果需要匹配整个单词并希望避免匹配子字符串,则正则表达式为您提供“单词边界锚”。例如:

indexOf('bar')

将在中找到bar3次bar, fubar, barmy,而

match(/\bbar\b/)

bar当它不是较长单词的一部分时才匹配。

正如您在评论中看到的那样,已经进行了一些比较,它们表明正则表达式可能比indexOf-速度快-如果它对性能至关重要,则可能需要分析代码。


2
我认为这是一个公平的问题,来自Perl的背景,等效的regex比快indexOf
LeeGee

1
相比之下,没有苹果能与橘子进行比较,因为琐碎的正则表达式可以优化为与一样快indexOf。我刚刚运行jsperf.com/substring-test,它声称“ regex不区分大小写”是最快的,并且比“ indexOf”快30%,我拒绝相信。
maaartinus

12

在这里,所有可能的方式(相对)搜索字符串

// 1.包含(在ES6中引入)

var string = "string to search for substring",
    substring = "sea";
string.includes(substring);

// 2. string.indexOf

var string = "string to search for substring",
    substring = "sea";
string.indexOf(substring) !== -1;

// 3. RegExp:测试

var string = "string to search for substring",
    expr = /sea/;  // no quotes here
expr.test(string);

// 4. string.match

var string = "string to search for substring",
    expr = "/sea/";
string.match(expr);

// 5。字符串搜索

var string = "string to search for substring",
    expr = "/sea/";
string.search(expr);

这是一个src:https//koukia.ca/top-6-ways-to-search-for-a-string-in-javascript-and-performance-benchmarks-ce3e9b81ad31

基准似乎专门针对es6 include而扭曲,请阅读注释。

在简历中:

如果您不需要比赛。=>或者您需要正则表达式,然后使用test。否则,es6 includeindexOf。仍在测试vs indexOf接近。

对于包括vs indexOf:

他们似乎是相同的:https://jsperf.com/array-indexof-vs-includes/4 (如果它是不同的,将是奇怪的,他们大多是执行相同的,除了他们公开的分歧检查此

并进行我自己的基准测试。此处是http://jsben.ch/fFnA0。 您可以对其进行测试(取决于浏览器)[测试多次],在这里它的性能如何(多次运行indexOf并包括一个节拍,另一个节拍,并且它们很接近)。所以他们是一样的。[此处使用与以上文章相同的测试平台]。

在此处输入图片说明 在此处输入图片说明

这里是长文本版本(长8倍) http://jsben.ch/wSBA2

在此处输入图片说明

同时测试了chrome和Firefox。

请注意,jsben.ch无法处理内存溢出(或有正确的限制。它不会显示任何消息),因此,如果您添加了8个以上的文本重复项(8个工作正常),结果可能会出错。但是结论是,对于非常大的文本,这三个函数都以相同的方式执行。否则,对于短的indexOf和include是相同的,并且测试要慢一些。或可以与Chrome中的外观相同(Firefox 60较慢)。

注意jsben.ch:如果结果不一致,请不要惊慌。尝试其他时间,看看是否一致。更改浏览器,有时它们只是完全错误地运行。错误或错误的内存处理。或者其他的东西。

例如:

在此处输入图片说明

这也是我在jsperf上的基准测试(更好的详细信息,并为多个浏览器处理图表)

(顶部是铬)

普通文本 https://jsperf.com/indexof-vs-includes-vs-test-2019
简历: include和indexOf具有相同的性能。测试较慢。

在此处输入图片说明 在此处输入图片说明 (似乎所有三个在色度上都表现相同)

长文本(比正常时间长12倍) https://jsperf.com/indexof-vs-includes-vs-test-2019-long-text-str/
简历: 这三者的表现相同。(Chrome和Firefox) 在此处输入图片说明

非常短字符串 https://jsperf.com/indexof-vs-includes-vs-test-2019-too-short-string/
简历:包括和的indexOf执行相同和测试慢。

在此处输入图片说明

注意:关于上述基准。对于很短的弦版本(jsperf),chrome有很大的错误。以我的眼神来看。两个indexOf都运行了大约60个样本,并且包含相同的方式(重复了很多次)。并测试得少一点,那么慢。不要被错误的图表所迷惑。显然是错误的。对于Firefox,相同的测试工作还可以,当然这是一个错误。

插图如下:(第一个图像是对Firefox的测试) 在此处输入图片说明 waaaa。突然indexOf成为超人。但是正如我所说,我进行了测试,并查看了大约60个样本。indexOf和include以及它们执行的都是相同的。jspref上的错误。除了这一点(可能是由于内存限制相关的问题)之外,其余所有内容都是一致的,它提供了更多细节。您会实时看到多少简单的事情发生。

最终简历

indexOf vs includes =>性能相同

测试=>对于短字符串或文本可能会更慢。与长文本相同。对于正则表达式引擎增加的开销,这是有意义的。在Chrome中,这似乎没有任何关系。


:thumbs-up:为了努力:)
Ajay Kumar Ganesh


6

您询问是否str.indexOf('target')还是str.match(/target/)应该优先。正如其他发布者所建议的那样,这些方法的用例和返回类型是不同的。第一个问:“str我首先可以在哪里找到'target'?” 第二个询问“是否str匹配正则表达式,如果匹配,则任何关联的捕获组的所有匹配项是什么?”

问题在于,从技术上讲,没有人设计出一个简单的问题“字符串是否包含子字符串?” 有一些明确设计用来做到这一点的东西:

var doesStringContainTarget = /target/.test(str);

使用有几个优点regex.test(string)

  1. 它返回一个布尔值,这就是您所关心的
  2. str.match(/target/)(和竞争对手str.indexOf('target'))性能更高
  3. 如果由于某种原因,strundefinednull,您将获得false(所需结果)而不是抛出TypeError

5

indexOf从理论上讲,当您只搜索纯文本时,使用应该比正则表达式更快,但是如果您担心性能,则应该自己做一些比较基准。

如果您愿意,match并且它可以满足您的需求,那么就快去吧。

对于它的价值,我在这一点上与您的同事同意:我将indexOf在搜索纯字符串时使用,match仅在需要正则表达式提供的额外功能时才使用etc。


4

明智的性能indexOf至少会比match。一切都取决于具体的实现。在决定使用哪个时,请问自己以下问题:

整数索引是否足够?我是否需要RegExp匹配结果的功能?


3

返回值不同

除了对性能的影响(其他答案可以解决)以外,还需要注意的是,每种方法的返回值都是不同的。因此,在不改变逻辑的情况下不能仅仅替换方法。

返回值.indexOfinteger

String指定值首次出现的调用对象内的索引,从开始搜索fromIndex如果找不到该值,则
返回-1

返回值.matcharray

一个包含整个匹配结果和任何用括号捕获的匹配结果的数组。如果没有匹配,则
返回null

因为如果调用字符串指定的值开头,则.indexOf返回,因此简单的真实测试将失败。0

例如:

鉴于这堂课...

class='DisablesGuiClass-2345-2d73-83hf-8293 redBorder' 

…每个的返回值都不同:

//  returns `0`, evaluates to `false`
if (string.indexOf('DisablesGuiClass-')) {
    … // this block is skipped.
}

//  returns `["DisablesGuiClass-"]`, evaluates to `true`
if (string.match(/DisablesGuiClass-/)) { 
    … // this block is run.
}

用return进行真实测试的正确方法.indexOf是针对-1

if (string.indexOf('DisablesGuiClass-') !== -1) {
//  ^returns `0`                        ^evaluates to `true`// this block is run.
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.