250

I'm working with a performance issue on JavaScript. So I just want to ask: what is the fastest way to check whether a string contains another substring (I just need the boolean value)? Could you please suggest your idea and sample snippet code?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Đinh Hồng Châu
  • 5,300
  • 15
  • 53
  • 90
  • Are you asking about a fixed substring, or do you need a regular expression (I'm a bit confused by the use of the `regex` tag)? – Tim Pietzcker Mar 14 '11 at 08:27
  • 1
    This post would be helpful .. http://stackoverflow.com/questions/1789945/javascript-string-contains – mtk Oct 16 '12 at 09:30
  • 1
    How about splitting the string to an array around whitespace and do an array intersection? http://stackoverflow.com/questions/1885557/simplest-code-for-array-intersection-in-javascript – giorgio79 Jan 12 '16 at 09:28
  • http://jsben.ch/#/aWxtF – EscapeNetscape Oct 21 '16 at 21:19

10 Answers10

415

You have three possibilites:

  1. Regular expression:

     (new RegExp('word')).test(str)
     // or
     /word/.test(str)
    
  2. indexOf:

     str.indexOf('word') !== -1
    
  3. includes:

     str.includes('word')
    

Regular expressions seem to be faster (at least in Chrome 10).

Performance test - short haystack
Performance test - long haystack


**Update 2011:**

It cannot be said with certainty which method is faster. The differences between the browsers is enormous. While in Chrome 10 indexOf seems to be faster, in Safari 5, indexOf is clearly slower than any other method.

You have to see and try for your self. It depends on your needs. For example a case-insensitive search is way faster with regular expressions.


Update 2018:

Just to save people from running the tests themselves, here are the current results for most common browsers, the percentages indicate performance increase over the next fastest result (which varies between browsers):

Chrome: indexOf (~98% faster) <-- wow
Firefox: cached RegExp (~18% faster)
IE11: cached RegExp(~10% faster)
Edge: indexOf (~18% faster)
Safari: cached RegExp(~0.4% faster)

Note that cached RegExp is: var r = new RegExp('simple'); var c = r.test(str); as opposed to: /simple/.test(str)

Makyen
  • 31,849
  • 12
  • 86
  • 121
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 5
    This may be a little faster only if the text-to-search-for is known before hand (i.e. not stored in a variable) because the regex is created by the JavaScript engine during parse time. If you want to search for a string contained in a variable inside another string variable, indexOf is the fastest because you'd need to create a RegExp object and process the string to escape special characters etc. – Stephen Chung Mar 14 '11 at 08:36
  • 2
    from experience, indexOf can be faster for case-insensitive search if you use .toLowerCase on whatever you're searching first – Hayk Saakian Jan 20 '13 at 23:05
  • I'm writing an Office 2013 App, using Microsoft's Office Javascript API, and using `indexOf` doesn't work. I'm not sure why. Using Regex though does. This is an edge case, but others might run into the same issue. – Kelderic Jun 06 '14 at 18:37
  • Any reason substr() is not one of the possible solutions? I'd guess it's a lot faster than the RegEx solution in many situations. I don't know how it compares to indexOf() though (so if you left it out because it always performs worse than indexOf() then that's fine, maybe add a note to that effect.) **EDIT:** [this JSperf link](http://jsperf.com/regexp-vs-indexof/12) shows some interesting results. Short version: indexOf() is the fastest of all methods, but this may vary based on string length and any repeating patterns. – Byson Dec 22 '14 at 15:04
  • 2
    @Bison: you can only use substr if you already know where to look. I focused only on generic solutions. – Felix Kling Dec 22 '14 at 15:22
  • @FelixKling Of course. I got to this topic searching for something slightly different (how to check if a string starts with another string). So while your solutions also apply to my situation, the reverse is not necessarily true. My bad. – Byson Dec 24 '14 at 10:55
  • I would be very very pleased if you can provide me with some details about node performance :) But i guess its the same as the chrome version since both use the v8 javascript engine – Playdome.io May 29 '17 at 16:46
  • Is Chrome doing any caching? If not that is one hell of a good performance! – Nathan Adams Mar 27 '18 at 09:30
  • The constant updating is phenomenal and extremely useful! Please keep maintaining this. :) – Jacob Jan 15 '19 at 20:35
  • as @marsibarsi said, is there any node comparison? – dcsan Jul 11 '19 at 22:19
  • I just chained them so quick one liner: `const doesExist = new RegExp('text to find').test(stringToTest);` sweet! – twknab Aug 08 '19 at 00:09
  • I'm not sure if the jsPerf test is correct for Chrome. I'm sure those are the results, but I'm guessing Chrome optimizes by noting the retest is the same, so it skips the search & serves a cached result. Only way to really test-test is by both a random target & random search string. – tomByrer Nov 08 '19 at 01:32
  • this answer doesn't account for `includes`, which other answers suggest is the fastest approach now. since this is the top answer, could you possibly update this? otherwise, it might lead people down a suboptimal path. thanks! – Crashalot May 05 '20 at 00:11
58

The Fastest

  1. (ES6) includes
    var string = "hello",
    substring = "lo";
    string.includes(substring);
  1. ES5 and older indexOf
    var string = "hello",
    substring = "lo";
    string.indexOf(substring) !== -1;

http://jsben.ch/9cwLJ

enter image description here

Community
  • 1
  • 1
Tính Ngô Quang
  • 4,400
  • 1
  • 33
  • 33
19

Does this work for you?

string1.indexOf(string2) >= 0

Edit: This may not be faster than a RegExp if the string2 contains repeated patterns. On some browsers, indexOf may be much slower than RegExp. See comments.

Edit 2: RegExp may be faster than indexOf when the strings are very long and/or contain repeated patterns. See comments and @Felix's answer.

Stephen Chung
  • 14,497
  • 1
  • 35
  • 48
  • but how does this compare to other methods? Is this the fastest, or is it just one of the many methods of doing so? – Chii Mar 14 '11 at 08:30
  • This should be fast since it is implemented by JavaScript itself (i.e. it runs native code). Any other method based on JavaScript code will be slower. If you know the exact string, a regex might be a bit faster (as the JavaScript engine does not have to walk the prototype chain to find .indexOf). – Stephen Chung Mar 14 '11 at 08:35
  • If you need case-insensitive search, then you'd definitely need to build a RegExp object and call `test`. – Stephen Chung Mar 14 '11 at 08:51
  • 3
    Just ran a test in Safari. `indexOf` is a magnitude slower than any other method. So it actually cannot be said which method is faster. It varies from browser to browser. – Felix Kling Mar 14 '11 at 09:10
  • @Felix, that's a good observation (never trust anything until you actually try it yourself)! I vague remembering something that says in strings with lots of repeated patterns, regex's should perform faster than a simple loop comparison implementation because regex's are compiled into state machines and it can back-track much quicker than simple loops -- which has to always back-track to the next character. +1 for doing the experiment and bringing this out! – Stephen Chung Mar 14 '11 at 09:23
  • @Felix, you're right. I think it is true that in regex's, if you don't use look-ahead and look-behind, the input string is scanned exactly once. It is an O(n) operation. For a simple indexOf implementation using loops, it is an O(n2) operation. So the overhead sustained by a RegExp may be compensated by its efficiency if the strings are long and there are repeated patterns! – Stephen Chung Mar 14 '11 at 09:29
10

In ES6, the includes() method is used to determine whether one string may be found within another string, returning true or false as appropriate.

var str = 'To be, or not to be, that is the question.';

console.log(str.includes('To be'));       // true
console.log(str.includes('question'));    // true
console.log(str.includes('nonexistent')); // false

Here is jsperf between

var ret = str.includes('one');

And

var ret = (str.indexOf('one') !== -1);

As the result shown in jsperf, it seems both of them perform well.

laggingreflex
  • 32,948
  • 35
  • 141
  • 196
zangw
  • 43,869
  • 19
  • 177
  • 214
  • 1
    Can I use "regex" inside, as includes' argument? Like: `str.includes("x|y")`; search for the literals "x" or "y" in the same call. – ptkato Apr 15 '16 at 02:56
  • @Patrick, Per the include doc, you cannot use `regex` in it. One work around for your question, `str.includes("x") || str.includes('y')` – zangw Apr 15 '16 at 03:27
  • As a result of the Chrome 59 JavaScript improvements, `indexOf` is significantly faster than `includes` (upwards of 1600% faster). It's unclear how a difference of 44 million iterations/sec and **777+ million** i/sec affects real-world performance, however mobile likely benefits enough that `indexOf` should be the ideal choice. – Chad Levy Sep 13 '18 at 20:06
7

I've found that using a simple for loop, iterating over all elements in the string and comparing using charAt performs faster than indexOf or Regex. The code and proof is available at JSPerf.

ETA: indexOf and charAt both perform similarly terrible on Chrome Mobile according to Browser Scope data listed on jsperf.com

wpg4665
  • 131
  • 1
  • 9
  • Strange that a hand made function is better than a built in one, but I guess this is because the needle is only one character. Still... – Moss Aug 16 '14 at 20:48
  • Tested in Chrome Mobile 36.0.1985.57 on Apple iPad (iOS 7.1.1). IndexOf is faster. Sorry – rpax Aug 30 '14 at 18:31
  • @rpax CharAt is still significantly faster on all platforms (based on the history from jsperf) _except_ for Chrome Mobile, where both IndexOf and CharAt equally perform very poorly compared to the desktop. – wpg4665 Sep 01 '14 at 01:31
  • 1
    I'd like to see how this performs in NodeJS, and also this isn't really a good example because you are only looking for one character vs a substring. – qodeninja Oct 07 '14 at 01:09
  • This isn't a valid answer at all. You are not searching for a substring, only the occurrence of one single character – Henrik Myntti Sep 08 '15 at 07:24
5

It's easy way to use .match() method to string.

var re = /(AND|OR|MAYBE)/;
var str = "IT'S MAYBE BETTER WAY TO USE .MATCH() METHOD TO STRING";
console.log('Do we found something?', Boolean(str.match(re)));

Wish you a nice day, sir!

Anton Danilchenko
  • 2,318
  • 1
  • 25
  • 24
4

I made a jsben.ch for you http://jsben.ch/#/aWxtF ...seems that indexOf is a bit faster.

EscapeNetscape
  • 2,892
  • 1
  • 33
  • 32
  • I forked that to made a more robust test. In Firefox I found less than 1% difference between methods, but on Chrome, `indexOf` murdered the competition, over 500% faster. – Slbox Apr 28 '21 at 18:28
  • I wonder if there is much difference between a boolean test and != -1 – user40521 Dec 16 '21 at 16:49
3

For finding a simple string, using the indexOf() method and using regex is pretty much the same: http://jsperf.com/substring - so choose which ever one that seems easier to write.

Chii
  • 14,540
  • 3
  • 37
  • 44
0

2022 string research benchmark

From Felix Kling's answer, and with tests I've done with given links.

Most used browser :

  1. Chrome (64%)
  2. Safari (19%)
  3. New Edge (4%)
  4. Firefox (3.26%)
  5. Samsung (2.86%)
  6. Opera (2.12%)

Chrome and NE are both based on Chromium => same performances.

ci = case insensitive
/ = same as left

Tests results

string length Firefox Safari Chromium
short cached RegExp ci cached RegExp ci indexOf & / ci worth
RegExp & / ci RegExp ci RegExp & / ci worse
long cached RegExp cached RE & / ci & reg ci indexOf worth
indexOf ci indexOf ci RegExp worse

Operations/sec comparison

browser Firefox Safari Chromium
cached RegExp 1.3M 425k 1.2M
diff 1.08x >
cached RegExp case sensitive 28M 31M 42M
diff 1.44/1.35x >
indexOf 27M 25M 1.9B
diff 70/76x >
indexOf case sensitive 13.8M 18.5M 1.9B
diff 137/103x >

Firefox best method : cached regexp case insensitive
Chrome best method : indexOf / indexOf case insensitive
Safari best method : cached RegExp case insensitive

Chrome has widely better performances than the two others.

Best compromise : indexOf : String.indexOf(substring) > -1.

Note : Remind that if you want to use the indexOf case sensitive way, if you operate a String.toLowerCase(), it adds some operations, so it's pretty similar to the insensitive way. In that case, you should be lowering your substring before the search process, not in it.

Regexes are really good for complex and/or pattern research/replacement, but not for a global research, and that in all languages, because of what it is.

NoxFly
  • 179
  • 1
  • 12
0

According to this site, include is much faster https://www.measurethat.net/Benchmarks/Show/13675/0/regextest-vs-stringincludes-vs-stringmatch

Rohit kumar
  • 11
  • 1
  • 1