关于正则表达式:JavaScript:indexOf与搜索字符串时的匹配?

JavaScript: indexOf vs. Match when Searching Strings?

除了可读性之外,使用之间是否存在任何可辨别的差异(可能性能)

1
str.indexOf("src")

1
str.match(/src/)

我个人更喜欢match(和regexp),但同事似乎走了另一条道路。 我们想知道它是否重要......?

编辑:

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

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

所以它的区别在于:

1
string.indexOf('DisablesGuiClass-');

VS

1
string.match(/DisablesGuiClass-/)


RegExp确实比indexOf慢(你可以在这里看到它),虽然通常这应该不是问题。使用RegExp,您还必须确保正确转义字符串,这是一个需要考虑的额外事项。

抛开这两个问题,如果两个工具完全符合您的需求,为什么不选择更简单的工具呢?


你的比较可能不完全公平。 indexOf与普通字符串一起使用,因此非常快; match采用正则表达式 - 当然它可能比较慢,但是如果你想进行正则表达式匹配,你将无法与indexOf相提并论。另一方面,正则表达式引擎可以进行优化,并且在过去几年中一直在提高性能。

在您的情况下,如果您要查找逐字字符串,indexOf就足够了。但是仍然有一个正则表达式的应用程序:如果你需要匹配整个单词并且想要避免匹配子字符串,那么正则表达式会给你"单词边界锚点"。例如:

1
indexOf('bar')

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

1
match(/\bbar\b/)

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

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


如果您尝试不区分大小写地搜索子字符串出现,则match似乎比indexOftoLowerCase()的组合更快

点击这里 - http://jsperf.com/regexp-vs-indexof/152


你问是否应该首选str.indexOf('target')str.match(/target/)。正如其他海报所建议的那样,这些方法的用例和返回类型是不同的。第一个问"我能在str中找到'target'?"第二个问"str匹配正则表达式,如果是,那么任何相关捕获组的所有匹配是什么?"

问题是,在技术上没有一个设计用于提出更简单的问题"字符串是否包含子字符串?"有明确设计的东西:

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

使用regex.test(string)有几个好处:

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

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

    如果您更喜欢match并且它足够快以满足您的需求,那就去吧。

    对于它的价值,我同意你的同事:我在搜索普通字符串时使用indexOf,并且只在我需要正则表达式提供的额外功能时才使用match等。


    性能方面indexOf至少会比match略快。这一切都归结为具体实施。在决定使用哪个时问问自己以下问题:

    Will an integer index suffice or do I
    need the functionality of a RegExp
    match result?


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

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

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

    // 2. string.indexOf

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

    // 3. RegExp:测试

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

    // 4. string.match

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

    // 5。 string.search

    1
    2
    3
    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包括扭曲,阅读评论。

    简历中:

    如果你不需要比赛。
    =>你需要正则表达式,所以使用测试。否则es6包含或indexOf。仍然测试与indexOf接近。

    对于includes vs indexOf:

    它们看起来是一样的:https://jsperf.com/array-indexof-vs-includes/4(如果它不同它会很奇怪,它们大多数表现相同,除了它们暴露的差异检查这个)

    并为我自己的基准测试。这是http://jsben.ch/fFnA0
    你可以测试它(它取决于浏览器)[多次测试]
    在这里它是如何执行的(多次运行indexOf并包括一个击败另一个,它们很接近)。所以他们是一样的。 [这里使用与上述文章相同的测试平台]。

    enter image description here
    enter image description here

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

    enter image description here

    测试了chrome和firefox,同样的事情。

    注意jsben.ch不处理内存溢出(或者没有正确限制。它没有显示任何消息)所以如果添加8个以上的文本复制(8个工作正常),结果可能会出错。但结论是对于非常大的文本,所有三个都以相同的方式执行。否则为简短的indexOf和包含相同,测试速度稍慢。或者可以与chrome中的相同(firefox 60它更慢)。

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

    例如:

    enter image description here

    这也是我对jsperf的基准测试(更好的细节,并处理多个浏览器的图形)

    (顶部是铬)

    普通文字
    https://jsperf.com/indexof-vs-includes-vs-test-2019
    resume:includes和indexOf具有相同的性能。测试慢一点。

    enter image description here
    enter image description here
    (似乎所有三个人在铬中表现相同)

    长文本(比正常长12倍)
    https://jsperf.com/indexof-vs-includes-vs-test-2019-long-text-str/
    简历:三者都表现相同。 (chrome和firefox)
    enter image description here

    非常短的字符串
    https://jsperf.com/indexof-vs-includes-vs-test-2019-too-short-string/
    resume:includes和indexOf执行相同并且测试速度较慢。

    enter image description here

    注意:关于上面的基准。对于非常短的字符串版本(jsperf),chrome有一个很大的错误。看着我的眼睛。 indexOf运行大约60个样本并包含相同的方式(重复很多次)。并且测试少一点,慢一点。
    不要被错误的图表所迷惑。这显然是错的。同样的测试工作对于firefox来说,肯定是一个bug。

    这里插图:(第一张图片是对firefox的测试)
    enter image description here
    waaaa。突然索引成为超人。但正如我所说,我做了测试,并查看了大约60个样本的数量。无论是indexOf还是包括,他们都表现相同。 jspref上的一个错误。除了这个(可能是因为内存限制相关的问题)所有其余的都是一致的,它提供了更多的细节。你会看到有多少简单的实时发生。

    最后的简历

    indexOf vs includes =>性能相同

    对于短字符串或文本,test =>可能会更慢。长文本也一样。这对正则表达式引擎添加的开销很有意义。在Chrome中它似乎根本没关系。


    返回值不同

    除了其他答案所解决的性能影响之外,重要的是要注意每种方法的返回值是不同的;所以这些方法不能仅仅在不改变逻辑的情况下被替换。

    返回值.indexOfinteger

    The index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex.
    Returns -1 if the value is not found.

    返回值.matcharray

    An Array containing the entire match result and any parentheses-captured matched results.
    Returns null if there were no matches.

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

    例如:

    鉴于这门课......

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

    ...每个的返回值会有所不同:

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

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

    使用.indexOf返回来运行truthy测试的正确方法是针对-1进行测试:

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

    记得Internet Explorer 8不理解indexOf
    但是,如果您的用户中没有人使用ie8(谷歌分析会告诉你),而不是省略这个答案。
    修复ie8的可能解决方案:
    如何在JavaScript中为Internet Explorer浏览器修复Array indexOf()


    只有当你真正需要它时,才总是使用indexOf来存在子串和match。即如果你在一个也可能包含altsrc的字符串中搜索单词src,那么aString.match(/\bsrc\b/)确实更合适。