Comment vérifier si une chaîne contient du texte d'un tableau de sous-chaînes en JavaScript?


163

Assez simple. En javascript, je dois vérifier si une chaîne contient des sous-chaînes contenues dans un tableau.


N'y a-t-il pas une map()fonction dans la nouvelle version HTML5-JavaScript? Je me souviens avoir lu quelque chose sur ce sujet ...
Martin Hennings

@Martin: Bon point, pas maptant que ça some. someaiderait, mais il faudrait lui passer une fonction.
TJ Crowder

Réponses:


224

Il n'y a rien de intégré qui fera cela pour vous, vous devrez écrire une fonction pour cela.

Si vous savez que les chaînes ne contiennent aucun des caractères spéciaux dans les expressions régulières, vous pouvez tricher un peu, comme ceci:

if (new RegExp(substrings.join("|")).test(string)) {
    // At least one match
}

... qui crée une expression régulière qui est une série d' alternatives pour les sous-chaînes que vous recherchez (par exemple, one|two) et teste pour voir s'il y a des correspondances pour l'une d'entre elles, mais si l'une des sous-chaînes contient des caractères spéciaux dans les expressions rationnelles ( *,[ , etc.), vous auriez à les échapper et vous êtes mieux faire juste la boucle ennuyeuse à la place.

Exemple en direct:


Dans un commentaire sur la question, Martin pose des questions sur la nouvelle Array.prototype.mapméthode dans ECMAScript5. mapn'est pas très utile, mais someest:

if (substrings.some(function(v) { return str.indexOf(v) >= 0; })) {
    // There's at least one
}

Exemple en direct:

Vous ne l'avez que sur les implémentations compatibles ECMAScript5, bien qu'il soit trivial de polyfill.


Mise à jour en 2020 : l' someexemple peut être plus simple avec une fonction de flèche (ES2015 +), et vous pouvez utiliser includesplutôt que indexOf:

if (substrings.some(v => str.includes(v))) {
    // There's at least one
}

Exemple en direct:

Ou même lancez- bindvous, même si pour moi la fonction de flèche est beaucoup plus lisible:

if (substrings.some(str.includes.bind(str))) {
    // There's at least one
}

Exemple en direct:


2
"Attention, cela signifie des frais généraux ..." mais il n'y a pas de quoi se soucier .
TJ Crowder

Vous pouvez étendre au- dessus solution en supprimant tous les caractères regex sauf le « | »: new RegExp(substrings.join("|").replace(/[^\w\s^|]/gi, '')).test(string).
user007

l'utilisation d'indexOf peut être trop floue et donner un résultat étrange. Il peut être simplement mis pour correspondre à la chaîne en utilisant l'opérateur égal. eg ('disconnect'.indexOf('connect') >= 0) === truebut('disconnect' === 'conenct') === false
kylewelspar

@halfcube: Hein? Je ne te comprends pas, j'en ai peur. Rien dans la réponse ci-dessus ne suggère que ce 'disconnect' === 'connect'sera autre chose false. De plus, ce indexOfn'est pas flou, c'est vraiment très clairement défini.
TJ Crowder

indexOfcorrespondra aux deux disconnectet connectoù, dans un cas que j'ai vécu, ce sont deux cas différents pour lesquels je veux renvoyer des résultats dans un conditionnel.
kylewelspar

54
var yourstring = 'tasty food'; // the string to check against


var substrings = ['foo','bar'],
    length = substrings.length;
while(length--) {
   if (yourstring.indexOf(substrings[length])!=-1) {
       // one of the substrings is in yourstring
   }
}

50

Solution une ligne

substringsArray.some(substring=>yourBigString.includes(substring))

Renvoie true\falsesi sous-chaîneexists\does'nt exist

Nécessite le support ES6


Excellente solution utilisant les fonctions fléchées
GuerillaRadio

7
Vous les enfants ... à l'époque où j'étais enfant, nous devions utiliser ces choses appelées boucles `` for '', et vous deviez utiliser plusieurs lignes et savoir si votre tableau était basé sur 1 ou zéro, oui ... la moitié du temps il a mal et a dû déboguer et rechercher un petit bugger appelé «i».
aamarks

25
function containsAny(str, substrings) {
    for (var i = 0; i != substrings.length; i++) {
       var substring = substrings[i];
       if (str.indexOf(substring) != - 1) {
         return substring;
       }
    }
    return null; 
}

var result = containsAny("defg", ["ab", "cd", "ef"]);
console.log("String was found in substring " + result);

1
le plus simple à comprendre!
Daryl H

De plus, il renvoie la première occurrence du mot dans la chaîne, ce qui est très utile. Pas seulement un vrai / faux.
Kai Noack

20

Pour les gens qui recherchent sur Google,

La réponse solide devrait être.

const substrings = ['connect', 'ready'];
const str = 'disconnect';
if (substrings.some(v => str === v)) {
   // Will only return when the `str` is included in the `substrings`
}

2
ou plus court: if (substrings.some (v => v === str)) {
kofifus

10
Notez qu'il s'agit d'une réponse à une question légèrement différente, qui demande si une chaîne contient du texte d'un tableau de sous-chaînes. Ce code vérifie si une chaîne est l' une des sous-chaînes. Cela dépend de ce que l'on entend par «contient», je suppose.
fcrick

8
var str = "texttexttext";
var arr = ["asd", "ghj", "xtte"];
for (var i = 0, len = arr.length; i < len; ++i) {
    if (str.indexOf(arr[i]) != -1) {
        // str contains arr[i]
    }
}

edit: Si l'ordre des tests n'a pas d'importance, vous pouvez utiliser ceci (avec une seule variable de boucle):

var str = "texttexttext";
var arr = ["asd", "ghj", "xtte"];
for (var i = arr.length - 1; i >= 0; --i) {
    if (str.indexOf(arr[i]) != -1) {
        // str contains arr[i]
    }
}

Votre premier exemple n'a pas besoin de la lenvariable, vérifiez simplement i < arr.length.
GreySage le

3

Si le tableau n'est pas volumineux, vous pouvez simplement effectuer une boucle et vérifier la chaîne par rapport à chaque sous-chaîne individuellement en utilisant indexOf(). Vous pouvez également construire une expression régulière avec des sous-chaînes comme alternatives, ce qui peut être plus efficace ou non.


Disons que nous avons une liste de 100 sous-chaînes. Quel moyen serait le plus efficace: RegExp ou boucle?
Diyorbek Sadullayev le

3

Fonction Javascript pour rechercher un tableau de balises ou de mots-clés à l'aide d'une chaîne de recherche ou d'un tableau de chaînes de recherche. (Utilise une méthode de tableau ES5 et des fonctions fléchées ES6 )

// returns true for 1 or more matches, where 'a' is an array and 'b' is a search string or an array of multiple search strings
function contains(a, b) {
    // array matches
    if (Array.isArray(b)) {
        return b.some(x => a.indexOf(x) > -1);
    }
    // string match
    return a.indexOf(b) > -1;
}

Exemple d'utilisation:

var a = ["a","b","c","d","e"];
var b = ["a","b"];
if ( contains(a, b) ) {
    // 1 or more matches found
}

2

Non pas que je suggère que vous alliez étendre / modifier Stringle prototype de, mais c'est ce que j'ai fait:

String.prototype.includes ()

String.prototype.includes = function (includes) {
    console.warn("String.prototype.includes() has been modified.");
    return function (searchString, position) {
        if (searchString instanceof Array) {
            for (var i = 0; i < searchString.length; i++) {
                if (includes.call(this, searchString[i], position)) {
                    return true;
                }
            }
            return false;
        } else {
            return includes.call(this, searchString, position);
        }
    }
}(String.prototype.includes);

console.log('"Hello, World!".includes("foo");',          "Hello, World!".includes("foo")           ); // false
console.log('"Hello, World!".includes(",");',            "Hello, World!".includes(",")             ); // true
console.log('"Hello, World!".includes(["foo", ","])',    "Hello, World!".includes(["foo", ","])    ); // true
console.log('"Hello, World!".includes(["foo", ","], 6)', "Hello, World!".includes(["foo", ","], 6) ); // false


2

En m'inspirant de la solution de TJ Crowder, j'ai créé un prototype pour résoudre ce problème:

Array.prototype.check = function (s) {
  return this.some((v) => {
    return s.indexOf(v) >= 0;
  });
};

2
substringsArray.every(substring=>yourBigString.indexOf(substring) === -1)

Pour un support complet;)


2

La meilleure réponse est ici: Ceci est également insensible à la casse

    var specsFilter = [.....];
    var yourString = "......";

    //if found a match
    if (specsFilter.some((element) => { return new RegExp(element, "ig").test(yourString) })) {
        // do something
    }

1

En utilisant underscore.js ou lodash.js, vous pouvez effectuer les opérations suivantes sur un tableau de chaînes:

var contacts = ['Billy Bob', 'John', 'Bill', 'Sarah'];

var filters = ['Bill', 'Sarah'];

contacts = _.filter(contacts, function(contact) {
    return _.every(filters, function(filter) { return (contact.indexOf(filter) === -1); });
});

// ['John']

Et sur une seule chaîne:

var contact = 'Billy';
var filters = ['Bill', 'Sarah'];

_.every(filters, function(filter) { return (contact.indexOf(filter) >= 0); });

// true

1

C'est super tard, mais je viens de rencontrer ce problème. Dans mon propre projet, j'ai utilisé ce qui suit pour vérifier si une chaîne était dans un tableau:

["a","b"].includes('a')     // true
["a","b"].includes('b')     // true
["a","b"].includes('c')     // false

De cette façon, vous pouvez prendre un tableau prédéfini et vérifier s'il contient une chaîne:

var parameters = ['a','b']
parameters.includes('a')    // true

1

s'appuyant sur la réponse de TJ Crowder

en utilisant RegExp échappé pour tester l'occurrence "au moins une fois" d'au moins une des sous-chaînes.

function buildSearch(substrings) {
  return new RegExp(
    substrings
    .map(function (s) {return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');})
    .join('{1,}|') + '{1,}'
  );
}


var pattern = buildSearch(['hello','world']);

console.log(pattern.test('hello there'));
console.log(pattern.test('what a wonderful world'));
console.log(pattern.test('my name is ...'));


1

Si vous travaillez avec une longue liste de sous-chaînes composées de "mots" complets séparés par des espaces ou tout autre caractère courant, vous pouvez être un peu intelligent dans votre recherche.

Commencez par diviser votre chaîne en groupes de X, puis X + 1, puis X + 2, ..., jusqu'à Y. X et Y devraient être le nombre de mots de votre sous-chaîne avec respectivement le moins et le plus grand nombre de mots. Par exemple, si X est 1 et Y est 4, "Alpha Beta Gamma Delta" devient:

"Alpha" "Bêta" "Gamma" "Delta"

"Alpha Beta" "Beta Gamma" "Gamma Delta"

"Alpha Beta Gamma" "Beta Gamma Delta"

"Alpha Beta Gamma Delta"

Si X est 2 et Y 3, alors vous omettez la première et la dernière ligne.

Vous pouvez désormais rechercher rapidement dans cette liste si vous l'insérez dans un Set (ou une Map), bien plus rapidement que par comparaison de chaînes.

L'inconvénient est que vous ne pouvez pas rechercher des sous-chaînes comme "ta Gamm". Bien sûr, vous pouvez permettre cela en divisant par caractère plutôt que par mot, mais vous auriez souvent besoin de créer un ensemble massif et le temps / mémoire passé à le faire l'emporte sur les avantages.


1

Pour un support complet (en plus des versions de @ricca ).

wordsArray = ['hello', 'to', 'nice', 'day']
yourString = 'Hello. Today is a nice day'.toLowerCase()
result = wordsArray.every(w => yourString.includes(w))
console.log('result:', result)


0

Vous pouvez vérifier comme ceci:

<!DOCTYPE html>
<html>
   <head>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
      <script>
         $(document).ready(function(){
         var list = ["bad", "words", "include"] 
         var sentence = $("#comments_text").val()

         $.each(list, function( index, value ) {
           if (sentence.indexOf(value) > -1) {
                console.log(value)
            }
         });
         });
      </script>
   </head>
   <body>
      <input id="comments_text" value="This is a bad, with include test"> 
   </body>
</html>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.