How to check whether a string contains a substring in JavaScript?

Solution 1

ECMAScript 6 introduced String.prototype.includes:

const string = "foo";
const substring = "oo";

console.log(string.includes(substring)); // true

String.prototype.includes is case-sensitive and is not supported by Internet Explorer without a polyfill.

In ECMAScript 5 or older environments, use String.prototype.indexOf, which returns -1 when a substring cannot be found:

var string = "foo";
var substring = "oo";

console.log(string.indexOf(substring) !== -1); // true


Solution 2

There is a String.prototype.includes in ES6:

"potato".includes("to");
> true

Note that this does not work in Internet Explorer or some other old browsers with no or incomplete ES6 support. To make it work in old browsers, you may wish to use a transpiler like Babel, a shim library like es6-shim, or this polyfill from MDN:

if (!String.prototype.includes) {
  String.prototype.includes = function(search, start) {
    'use strict';
    if (typeof start !== 'number') {
      start = 0;
    }
if (start + search.length > this.length) {
  return false;
} else {
  return this.indexOf(search, start) !== -1;
}

}; }


Solution 3

Another alternative is KMP (Knuth–Morris–Pratt).

The KMP algorithm searches for a length-m substring in a length-n string in worst-case O(n+m) time, compared to a worst-case of O(nm) for the naive algorithm, so using KMP may be reasonable if you care about worst-case time complexity.

Here's a JavaScript implementation by Project Nayuki, taken from https://www.nayuki.io/res/knuth-morris-pratt-string-matching/kmp-string-matcher.js:

// Searches for the given pattern string in the given text string using the Knuth-Morris-Pratt string matching algorithm.
// If the pattern is found, this returns the index of the start of the earliest match in 'text'. Otherwise -1 is returned.

function kmpSearch(pattern, text) {
  if (pattern.length == 0)
    return 0; // Immediate match

// Compute longest suffix-prefix table var lsp = [0]; // Base case for (var i = 1; i < pattern.length; i++) { var j = lsp[i - 1]; // Start by assuming we’re extending the previous LSP while (j > 0 && pattern[i] !== pattern[j]) j = lsp[j - 1]; if (pattern[i] === pattern[j]) j++; lsp.push(j); }

// Walk through text string var j = 0; // Number of chars matched in pattern for (var i = 0; i < text.length; i++) { while (j > 0 && text[i] != pattern[j]) j = lsp[j - 1]; // Fall back in the pattern if (text[i] == pattern[j]) { j++; // Next char matched, increment position if (j == pattern.length) return i - (j - 1); } } return -1; // Not found }

console.log(kmpSearch(‘ays’, ‘haystack’) != -1) // true console.log(kmpSearch(‘asdf’, ‘haystack’) != -1) // false