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.

PercivalMcGullicuddy
la source
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:

TJ Crowder
la source
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
   }
}
Raveren
la source
50

Solution une ligne

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

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

Nécessite le support ES6

Praveena
la source
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);
Jim Blackler
la source
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`
}
Kylewelsby
la source
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]
    }
}
utilisateur
la source
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.

Gintautas Miliauskas
la source
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
}
David Douglas
la source
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

akinuri
la source
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;
  });
};
Alavry
la source
2
substringsArray.every(substring=>yourBigString.indexOf(substring) === -1)

Pour un support complet;)

ricca
la source
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
    }
Adel Mourad
la source
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
BuffMcBigÉnorme
la source
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
Lincoln Anders
la source
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 ...'));

DhavalW
la source
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.

Emil Norén
la source
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)

TitanFighter
la source
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>
Dhaval Soni
la source
-1
let obj = [{name : 'amit'},{name : 'arti'},{name : 'sumit'}];
let input = 'it';

Utilisez le filtre:

obj.filter((n)=> n.name.trim().toLowerCase().includes(input.trim().toLowerCase()))
ArtiSK
la source
s'il vous plaît visitez et vérifiez comment répondre à une question .
Yunus Temurlenk le
@YunusTemurlenk thnx
ArtiSK