Как проверить, содержит ли строка текст из массива подстрок в JavaScript?

Довольно прямолинейно. В javascript мне нужно проверить, содержит ли строка какие-либо подстроки, содержащиеся в массиве.


person PercivalMcGullicuddy    schedule 07.04.2011    source источник
comment
Разве в новой версии HTML5-JavaScript нет функции map()? Я помню, что читал что-то по этой теме ...   -  person Martin Hennings    schedule 07.04.2011
comment
@Martin: Хороший аргумент, не столько map, сколько some. some поможет, но вам придется передать ему функцию.   -  person T.J. Crowder    schedule 07.04.2011


Ответы (19)


Нет ничего встроенного, что могло бы сделать это за вас, вам придется написать для этого функцию.

Если вы знаете, что строки не содержат каких-либо специальных символов в регулярных выражениях, вы можете немного схитрить, например:

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

... который создает регулярное выражение, представляющее собой серию чередований для искомых подстрок (например, one|two), и проверяет, есть ли совпадения для какой-либо из них, но если какая-либо из подстроки содержат любые символы, которые являются специальными в регулярных выражениях (*, [ и т. д.), вам придется сначала их экранировать, и вместо этого вам лучше просто выполнить скучный цикл. Для получения информации о том, как их избежать, см. ответы на этот вопрос.

Живой пример:

var substrings = ["one", "two", "three"];
var str;

// Setup
console.log("Substrings: " + substrings.join(","));

// Try it where we expect a match
str = "this has one";
if (new RegExp(substrings.join("|")).test(str)) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

// Try it where we DON'T expect a match
str = "this doesn't have any";
if (new RegExp(substrings.join("|")).test(str)) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}


В комментарии к вопросу Мартин спрашивает о новом методе Array.prototype.map в ECMAScript5. map не очень помогает, но some:

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

Живой пример:

var substrings = ["one", "two", "three"];
var str;

// Setup
console.log("Substrings: " + substrings.join(","));

// Try it where we expect a match
str = "this has one";
if (substrings.some(function(v) { return str.indexOf(v) >= 0; })) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

// Try it where we DON'T expect a match
str = "this doesn't have any";
if (substrings.some(function(v) { return str.indexOf(v) >= 0; })) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

Он есть только в реализациях, совместимых с ECMAScript5, хотя полифил - тривиально.


Обновление в 2020 году: пример some можно упростить с помощью функции стрелки (ES2015 +), и вы можете использовать includes вместо indexOf:

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

Живой пример:

const substrings = ["one", "two", "three"];
let str;

// Setup
console.log("Substrings: " + substrings.join(","));

// Try it where we expect a match
str = "this has one";
if (substrings.some(v => str.includes(v))) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

// Try it where we DON'T expect a match
str = "this doesn't have any";
if (substrings.some(v => str.includes(v))) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

Или даже бросить на него bind, хотя для меня стрелочная функция намного читабельнее:

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

Живой пример:

const substrings = ["one", "two", "three"];
let str;

// Setup
console.log("Substrings: " + substrings.join(","));

// Try it where we expect a match
str = "this has one";
if (substrings.some(str.includes.bind(str))) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

// Try it where we DON'T expect a match
str = "this doesn't have any";
if (substrings.some(str.includes.bind(str))) {
    console.log("Match using '" + str + "'");
} else {
    console.log("No match using '" + str + "'");
}

person T.J. Crowder    schedule 07.04.2011
comment
Имейте в виду, это действительно означает некоторые накладные расходы ... но не о чем беспокоиться. - person T.J. Crowder; 27.06.2013
comment
Вы можете расширить указанное выше решение, удалив все символы регулярного выражения, кроме '|': new RegExp(substrings.join("|").replace(/[^\w\s^|]/gi, '')).test(string). - person user007; 09.05.2015
comment
использование indexOf может быть слишком нечетким и давать странный результат. Его можно просто сопоставить строке с помощью оператора равенства. например ('disconnect'.indexOf('connect') >= 0) === true но ('disconnect' === 'conenct') === false - person kylewelsby; 13.06.2015
comment
@halfcube: А? Боюсь, я вас не понимаю. Ничто в приведенном выше ответе не предполагает, что 'disconnect' === 'connect' будет чем угодно, кроме false. Кроме того, indexOf не является расплывчатым, он действительно очень четко определен. - person T.J. Crowder; 13.06.2015
comment
indexOf будет соответствовать как disconnect, так и connect, где в случае, который я испытал, это два разных случая, для которых я хочу вернуть результаты в условном выражении. - person kylewelsby; 15.06.2015
comment
@halfcube: Верно, цель ОП: поиск в строке любой из нескольких подстрок. Если бы они искали точные совпадения, мы бы использовали return str === v;, а не return str.indexOf(v) >= 0;. Но они специально ищут подстроки. - person T.J. Crowder; 15.06.2015
comment
Я не уверен, почему, но у меня это не работает с модификатором /g. Иногда я получаю истину, а иногда ложь, даже при повторной проверке в отладчике webstorm во время паузы ... и я также вижу в узле. - person chovy; 24.02.2017
comment
@chovy: задайте вопрос с минимальным воспроизводимым примером. Но помните, что объекты регулярных выражений с флагом g имеют состояние, которое они сохраняют от одного использования до следующего, что, вероятно, является тем, о чем вы спотыкаетесь. - person T.J. Crowder; 24.02.2017
comment
Когда вы говорите «никаких специальных символов», вы имеете в виду фактическую строку, которую вы тестируете, или просто шаблон регулярного выражения? У меня есть специальные символы в строке, на которой я хочу проверить регулярное выражение. Ваш .some пример отлично работает - person chovy; 24.02.2017
comment
@chovy: Я имею в виду, что если ваша строка "24.7" и вы хотите соответствовать именно этому, вам нужно избежать этого . перед передачей строки в new RegExp, потому что в противном случае это будет токен регулярного выражения . (здесь любой символ). - person T.J. Crowder; 24.02.2017
comment
Я делаю re.test(text), и в половине случаев это дает мне ложь, а в другой - правду. Ваш .some работает нормально. - person chovy; 25.02.2017
comment
@chovy: Это из-за флага g и состояния, в котором находится регулярное выражение. Если вы используете test, вам не нужен флаг g. - person T.J. Crowder; 25.02.2017
comment
это многострочная строка, я думал, что для многострочных строк требуется модификатор g. - person chovy; 26.02.2017
comment
@chovy: Нет, g и многострочные строки не имеют ничего общего друг с другом. - person T.J. Crowder; 26.02.2017
comment
Perl regex они делают. - person chovy; 26.02.2017
comment
@chovy: При всем уважении, я думаю, вы ошибаетесь, но это не важно; это JavaScript. Если у вас возникнут дополнительные проблемы с этим, пожалуйста, задайте вопрос, а не комментарии. - person T.J. Crowder; 26.02.2017
comment
PCRE действительно этого требует. - person chovy; 26.02.2017
comment
@chovy: Ну, без цитаты, я откровенно сомневаюсь, но опять же, это действительно не имеет значения. - person T.J. Crowder; 26.02.2017
comment
Это не работает, когда вам нужно проверить специальный символ регулярного выражения, например | или (), поэтому я предпочитаю итерацию, но я думаю, что она будет иметь сложность n * m - person isundil; 02.11.2017
comment
@isundil: Я отметил это в ответе. Вы просто должны быть уверены, что избежали их. - person T.J. Crowder; 02.11.2017
comment
Напомним, что метод RegExp также возвращает частичные совпадения, например. onewffeq. - person Preben Tjemsland; 10.08.2020
comment
@PrebenTjemsland - Спасибо. Да, ОП сказал, что они хотели. Если бы им нужно было полное совпадение, они использовали бы indexOf (или более новый includes) в массиве строк, передавая строку для их проверки. - person T.J. Crowder; 10.08.2020
comment
Думаю, нам тоже следует обрабатывать пустые строки ... substrings.some(v => v !== '' && str.includes(v)) - person Freddy Daniel; 19.11.2020

Однострочное решение

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

Возвращает true\false, если подстрока exists\does'nt exist

Требуется поддержка ES6

person Praveena    schedule 21.09.2017
comment
Отличное решение с использованием стрелочных функций - person GuerillaRadio; 10.10.2017
comment
Вы, дети ... когда я был ребенком, нам приходилось использовать эти вещи, называемые циклами for, и вам приходилось использовать несколько строк и знать, основан ли ваш массив на 1 или на нуле, да ... в половине случаев у вас есть это было неправильно, и пришлось отлаживать и высматривать маленького баггера под названием «i». - person aamarks; 21.04.2018
comment
Действительно красивое, чистое решение. - person Michael F.; 19.11.2020

Для людей, которые ищут в Google,

Твердый ответ должен быть.

const substrings = ['connect', 'ready'];
const str = 'disconnect';
if (substrings.some(v => str === v)) {
   // Will only return when the `str` is included in the `substrings`
}
person kylewelsby    schedule 13.06.2015
comment
или короче: if (substrings.some (v = ›v === str)) { - person kofifus; 13.09.2017
comment
Обратите внимание, что это ответ на несколько иной вопрос, который спрашивает, содержит ли строка текст из массива подстрок. Этот код проверяет, является ли строка одной из подстрок. Полагаю, это зависит от того, что имеется в виду под словом «содержит». - person fcrick; 29.05.2018

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

изменить: если порядок тестов не имеет значения, вы можете использовать это (только с одной переменной цикла):

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]
    }
}
person user    schedule 07.04.2011
comment
В вашем первом примере переменная len не требуется, просто отметьте i < arr.length. - person GreySage; 26.02.2020

Лучший ответ здесь: он также нечувствителен к регистру

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

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

Если массив невелик, вы можете просто зациклить и проверить строку по каждой подстроке индивидуально, используя indexOf(). В качестве альтернативы вы можете создать регулярное выражение с подстроками в качестве альтернативы, что может быть или не быть более эффективным.

person Gintautas Miliauskas    schedule 07.04.2011
comment
Допустим, у нас есть список из 100 подстрок. Какой способ будет более эффективным: регулярное выражение или цикл? - person Diyorbek Sadullaev; 28.06.2020

Функция Javascript для поиска по массиву тегов или ключевых слов с использованием строки поиска или массива строк поиска. (Использует ES5 некоторый метод массива и 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;
}

Пример использования:

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

Не то чтобы я предлагаю вам пойти и расширить / изменить прототип String, но вот что я сделал:

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

person akinuri    schedule 20.02.2018

Это очень поздно, но я столкнулся с этой проблемой. В моем собственном проекте я использовал следующее, чтобы проверить, находится ли строка в массиве:

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

Таким образом, вы можете взять предопределенный массив и проверить, содержит ли он строку:

var parameters = ['a','b']
parameters.includes('a')    // true
person Lincoln Anders    schedule 20.02.2018
comment
это самый чистый ответ здесь. огромное спасибо! - person Abid Khairy; 13.06.2021

Рисунок из книги T.J. Решение Crowder, я создал прототип для решения этой проблемы:

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

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

За полную поддержку;)

person ricca    schedule 09.04.2020

Для полной поддержки (в дополнение к версиям @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)

person TitanFighter    schedule 19.06.2020

Используя underscore.js или lodash.js, вы можете делать следующее с массивом строк:

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

И на одной строке:

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

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

// true
person BuffMcBigHuge    schedule 08.11.2017

основываясь на ответе Т.Дж. Краудера

использование экранированного регулярного выражения для проверки наличия "хотя бы один раз" хотя бы одной из подстрок.

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

person DhavalW    schedule 27.02.2018

Если вы работаете с длинным списком подстрок, состоящим из полных «слов», разделенных пробелами, или любого другого общего символа, вы можете быть немного умнее в своем поиске.

Сначала разделите вашу строку на группы по X, затем X + 1, затем X + 2, ..., вплоть до Y. X и Y должны быть количеством слов в вашей подстроке с наименьшим и наибольшим количеством слов соответственно. Например, если X равно 1, а Y равно 4, "Альфа-Бета-Гамма-дельта" станет:

«Альфа» «Бета» «Гамма» «Дельта»

«Альфа Бета» «Бета Гамма» «Гамма Дельта»

«Альфа Бета Гамма» «Бета Гамма Дельта»

«Альфа Бета Гамма Дельта»

Если бы X было 2, а Y было бы 3, вы бы опускали первую и последнюю строки.

Теперь вы можете быстро искать в этом списке, если вставляете его в Set (или Map), намного быстрее, чем при сравнении строк.

Обратной стороной является то, что вы не можете искать такие подстроки, как «ta Gamm». Конечно, вы можете учесть это, разбивая по символам, а не по словам, но тогда вам часто придется создавать массивный Set, и время / память, потраченные на это, перевешивают преимущества.

person Emil Norén    schedule 15.05.2019

convert_to_array = function (sentence) {
     return sentence.trim().split(" ");
};

let ages = convert_to_array ("I'm a programmer in javascript writing script");

function confirmEnding(string) {
let target = "ipt";
    return  (string.substr(-target.length) === target) ? true : false;
}

function mySearchResult() {
return ages.filter(confirmEnding);
}

mySearchResult();

вы можете проверить это и вернуть массив совпадающих слов с помощью фильтра

person Alemoh Rapheal Baja    schedule 07.09.2020

Проверить можно так:

<!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>
person Dhaval Soni    schedule 16.12.2019

let obj = [{name : 'amit'},{name : 'arti'},{name : 'sumit'}];
let input = 'it';

Использовать фильтр:

obj.filter((n)=> n.name.trim().toLowerCase().includes(input.trim().toLowerCase()))
person ArtiSK    schedule 17.02.2020
comment
посетите и проверьте как ответить на вопрос. - person Yunus Temurlenk; 17.02.2020
comment
@YunusTemurlenk спасибо - person ArtiSK; 25.02.2020

person    schedule
comment
самый простой для понимания! - person Daryl H; 14.07.2014
comment
Кроме того, он возвращает первое появление слова в строке, что очень полезно. Не только правда / ложь. - person Avatar; 21.05.2020
comment
что такое эквивалент es6? - person Ridhwaan Shakeel; 20.06.2021