¿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.


¿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:


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
   }
}

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


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);

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`
}

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

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.


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
}

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


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;
  });
};

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

Para soporte completo;)


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
    }

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

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

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 ...'));


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.


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)


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>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.