¿Cómo verificar si una cadena contiene texto de una matriz de subcadenas en JavaScript?

163

Muy claro. En javascript, necesito verificar si una cadena contiene alguna subcadena contenida en una matriz.

PercivalMcGullicuddy
fuente
¿No hay una map()función en la nueva versión HTML5-JavaScript? Recuerdo haber leído algo sobre ese tema ...
Martin Hennings
@ Martin: Buen punto, no maptanto como some. someayudaría, pero tendrías que pasarle una función.
TJ Crowder

Respuestas:

224

No hay nada incorporado que lo haga por usted, tendrá que escribir una función para ello.

Si sabe que las cadenas no contienen ninguno de los caracteres que son especiales en las expresiones regulares, puede hacer un poco de trampa, así:

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

... que crea una expresión regular que es una serie de alternancias para las subcadenas que está buscando (por ejemplo, one|two) y pruebas para ver si hay coincidencias para alguna de ellas, pero si alguna de las subcadenas contiene caracteres especiales en expresiones regulares ( *, [, etc.), que lo tienes que escapar de ellos primero y que está mejor simplemente haciendo el bucle aburrida en su lugar.

Ejemplo en vivo:


En un comentario sobre la pregunta, Martin pregunta sobre el nuevo Array.prototype.mapmétodo en ECMAScript5. mapno es de mucha ayuda, pero somees:

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

Ejemplo en vivo:

Solo lo tiene en implementaciones compatibles con ECMAScript5, aunque es trivial para polyfill.


Actualización en 2020 : el someejemplo puede ser más simple con una función de flecha (ES2015 +), y puede usar en includeslugar de indexOf:

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

Ejemplo en vivo:

O incluso lanzarlo bind, aunque para mí la función de flecha es mucho más legible:

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

Ejemplo en vivo:

TJ Crowder
fuente
2
"Eso sí, significa algunos gastos generales ..." pero nada de lo que preocuparse .
TJ Crowder
Puede extenderse por encima de la solución mediante la eliminación de todos los caracteres de expresiones regulares, excepto el '|': new RegExp(substrings.join("|").replace(/[^\w\s^|]/gi, '')).test(string).
user007
El uso de indexOf puede ser demasiado confuso y producir un resultado extraño. Simplemente se puede poner para que coincida con la cadena utilizando el operador igual. por ejemplo, ('disconnect'.indexOf('connect') >= 0) === truepero('disconnect' === 'conenct') === false
kylewelsby
@halfcube: ¿Eh? No te entiendo, me temo. Nada en la respuesta anterior sugiere que 'disconnect' === 'connect'será todo menos eso false. Además, indexOfno es borroso, está muy claramente definido.
TJ Crowder
indexOfcoincidirá con ambos disconnecty connectdonde en un caso que he experimentado, estos son dos casos diferentes para los que quiero devolver resultados en condicional.
kylewelsby
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
fuente
50

Solución de una línea

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

Devuelve true\falsesi la subcadenaexists\does'nt exist

Necesita soporte para ES6

Praveena
fuente
Gran solución con funciones de flecha
GuerillaRadio
77
Chicos ... cuando era niño teníamos que usar estas cosas llamadas bucles 'for', y tenía que usar varias líneas y saber si su matriz estaba basada en 1 o cero, sí ... la mitad del tiempo que tenía se equivocó y tuvo que depurar y buscar un pequeño insecto llamado '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
fuente
1
¡El más fácil de entender!
Daryl H
Además, devuelve la primera aparición de la palabra en la cadena, lo cual es muy útil. No solo un verdadero / falso.
Kai Noack
20

Para las personas que buscan en Google,

La respuesta sólida debería ser.

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
fuente
2
o más corto: if (substrings.some (v => v === str)) {
kofifus
10
Tenga en cuenta que esta es una respuesta a una pregunta ligeramente diferente, que pregunta si una cadena contiene texto de una matriz de subcadenas. Este código verifica si una cadena es una de las subcadenas. Depende de lo que se entiende por "contiene", supongo.
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]
    }
}

editar: si el orden de las pruebas no importa, puede usar esto (con solo una variable de bucle):

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]
    }
}
usuario
fuente
Su primer ejemplo no necesita la lenvariable, solo verifique i < arr.length.
GreySage
3

Si la matriz no es grande, puede simplemente hacer un bucle y verificar la cadena con cada subcadena individualmente indexOf(). Alternativamente, podría construir una expresión regular con subcadenas como alternativas, que pueden o no ser más eficientes.

Gintautas Miliauskas
fuente
Digamos que tenemos una lista de 100 subcadenas. ¿Qué forma sería más eficiente: RegExp o loop?
Diyorbek Sadullayev
3

Función Javascript para buscar una matriz de etiquetas o palabras clave utilizando una cadena de búsqueda o una matriz de cadenas de búsqueda. (Utiliza ES5 algún método de matriz y funciones de flecha 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;
}

Ejemplo de uso:

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

No es que te sugiera que vayas y extiendas / modifiques Stringel prototipo, pero esto es lo que he hecho:

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
fuente
2

A partir de la solución de TJ Crowder, creé un prototipo para tratar este problema:

Array.prototype.check = function (s) {
  return this.some((v) => {
    return s.indexOf(v) >= 0;
  });
};
alavry
fuente
2
substringsArray.every(substring=>yourBigString.indexOf(substring) === -1)

Para soporte completo;)

ricca
fuente
2

La mejor respuesta está aquí: esto también distingue entre mayúsculas y minúsculas

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

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

Usando underscore.js o lodash.js, puede hacer lo siguiente en una matriz de cadenas:

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']

Y en una sola cadena:

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

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

// true
BuffMcBigHuge
fuente
1

Esto es muy tarde, pero me encontré con este problema. En mi propio proyecto, utilicé lo siguiente para verificar si una cadena estaba en una matriz:

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

De esta manera, puede tomar una matriz predefinida y verificar si contiene una cadena:

var parameters = ['a','b']
parameters.includes('a')    // true
Lincoln Anders
fuente
1

aprovechando la respuesta de TJ Crowder

usando RegExp escapado para probar la aparición de "al menos una vez", de al menos una de las subcadenas.

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
fuente
1

Si está trabajando con una larga lista de subcadenas que consisten en "palabras" completas separadas por espacios o cualquier otro carácter común, puede ser un poco inteligente en su búsqueda.

Primero divida su cadena en grupos de X, luego X + 1, luego X + 2, ..., hasta Y. X e Y deben ser el número de palabras en su subcadena con la menor cantidad de palabras, respectivamente. Por ejemplo, si X es 1 e Y es 4, "Alpha Beta Gamma Delta" se convierte en:

"Alfa" "Beta" "Gamma" "Delta"

"Alfa Beta" "Beta Gamma" "Delta Gamma"

"Alfa Beta Gamma" "Beta Gamma Delta"

"Alfa Beta Gamma Delta"

Si X sería 2 e Y sería 3, entonces omitirías la primera y la última fila.

Ahora puede buscar en esta lista rápidamente si la inserta en un Conjunto (o un Mapa), mucho más rápido que mediante la comparación de cadenas.

La desventaja es que no puede buscar subcadenas como "ta Gamm". Por supuesto, podría permitir eso dividiéndolo por carácter en lugar de por palabra, pero luego a menudo necesitaría construir un conjunto masivo y el tiempo / memoria dedicado a hacerlo supera los beneficios.

Emil Norén
fuente
1

Para soporte completo (adicionalmente a las versiones 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
fuente
0

Puedes marcar así:

<!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
fuente
-1
let obj = [{name : 'amit'},{name : 'arti'},{name : 'sumit'}];
let input = 'it';

Usar filtro:

obj.filter((n)=> n.name.trim().toLowerCase().includes(input.trim().toLowerCase()))
ArtiSK
fuente
Visite y verifique cómo responder una pregunta .
Yunus Temurlenk
@YunusTemurlenk thnx
ArtiSK