Hoe controleer je of een tekenreeks een subtekenreeks in JavaScript bevat?

Normaal gesproken zou ik een String.contains()methode verwachten, maar die lijkt er niet te zijn.

Wat is een redelijke manier om dit te controleren?


Antwoord 1, autoriteit 100%

ECMAScript 6 introduceerde String.prototype.includes:

const string = "foo";
const substring = "oo";
console.log(string.includes(substring));

Antwoord 2, autoriteit 5%

Er is een String.prototype.includesin ES6:

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

Merk op dat deze niet werkt in Internet Explorer of sommige andere oude browserszonder of onvolledige ES6-ondersteuning. Om het in oude browsers te laten werken, wil je misschien een transpiler gebruiken zoals Babel, een shim-bibliotheek zoals es6-shim, of deze polyfill van 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;
    }
  };
}

Antwoord 3

Een ander alternatief is KMP(Knuth –Morris–Pratt).

Het KMP-algoritme zoekt naar een lengte-msubtekenreeks in een lengte-ntekenreeks in het slechtste geval O(n+m) tijd, vergeleken met een worst-case van O(nm) voor het naïeve algoritme, dus het gebruik van KMP kan redelijk zijn als je er om geeft over tijdscomplexiteit in het slechtste geval.

Hier is een JavaScript-implementatie door Project Nayuki, afkomstig van 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.charAt(i) != pattern.charAt(j))
      j = lsp[j - 1];
    if (pattern.charAt(i) == pattern.charAt(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.charAt(i) != pattern.charAt(j))
      j = lsp[j - 1]; // Fall back in the pattern
    if (text.charAt(i) == pattern.charAt(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

Other episodes