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

163

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

PercivalMcGullicuddy
источник
Нет ли map()функции в новой HTML5-JavaScript-версии? Я помню, что читал что-то на эту тему ...
Мартин Хеннингс
@ Мартин: Хороший вопрос, не mapтак много, как some. someпомогло бы, но вы должны были бы передать это функции.
TJ Crowder

Ответы:

224

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

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

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

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

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


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

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

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

У вас есть только в ECMAScript5-совместимых реализациях, хотя это тривиально для polyfill.


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

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

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

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

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

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

TJ Crowder
источник
2
«Имейте в виду, это означает некоторые накладные расходы ...», но не о чем беспокоиться .
TJ Crowder
Вы можете расширить выше решение, удалив все символы регулярных выражений , кроме «|»: new RegExp(substrings.join("|").replace(/[^\w\s^|]/gi, '')).test(string).
user007
использование indexOf может быть слишком нечетким и давать странный результат. Это может быть просто помещено, чтобы соответствовать строке, используя оператор равенства. например, ('disconnect'.indexOf('connect') >= 0) === trueно('disconnect' === 'conenct') === false
kylewelsby
@halfcube: А? Я не понимаю тебя, я боюсь. Ничто в ответе выше не предполагает, что 'disconnect' === 'connect'это будет что-либо кроме false. Кроме того, indexOfэто не нечетко, это действительно очень четко определено.
TJ Crowder
indexOfбудет соответствовать обоим, disconnectи connectгде в случае, в котором я находился, это два разных случая, для которых я хочу вернуть результаты в условном выражении.
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
источник
50

Одноканальное решение

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

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

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

Praveena
источник
Отличное решение с использованием функций стрелок
GuerillaRadio
7
Вы, дети ... когда я был ребенком, мы должны были использовать такие вещи, как циклы for, и вы должны были использовать несколько строк и знать, был ли ваш массив на основе 1 или нуля, да ... в половину времени вы получили это неправильно и пришлось отлаживать и высматривать маленького жучка под названием «я».
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
проще всего понять!
Дэрил Х
Кроме того, он возвращает первое вхождение слова в строку, что очень полезно. Не только правда / ложь.
Кай Ноак
20

Для людей, гуглящих,

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

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
источник
2
или короче: if (substrings.some (v => v === str)) {
kofifus
10
Обратите внимание, что это ответ на немного другой вопрос, который спрашивает, содержит ли строка текст из массива подстрок. Этот код проверяет , является ли строка является одним из подстрок. Зависит от того, что подразумевается под «содержит», я полагаю.
ФКрик
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: если порядок тестов не имеет значения, вы можете использовать это (только с одной переменной цикла):

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]
    }
}
пользователь
источник
Ваш первый пример не нуждается в lenпеременной, просто проверьте i < arr.length.
GreySage
3

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

Гинтаутас Миляускас
источник
Допустим, у нас есть список из 100 подстрок. Какой способ будет более эффективным: RegExp или цикл?
Диёрбек Садуллаев
3

Функция 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
}
Дэвид Дуглас
источник
2

Не то чтобы я предлагал вам пойти и расширить / модифицировать 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

akinuri
источник
2

На основе решения TJ Crowder я создал прототип для решения этой проблемы:

Array.prototype.check = function (s) {
  return this.some((v) => {
    return s.indexOf(v) >= 0;
  });
};
alavry
источник
2
substringsArray.every(substring=>yourBigString.indexOf(substring) === -1)

Для полной поддержки;)

Рикка
источник
2

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

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

    //if found a match
    if (specsFilter.some((element) => { return new RegExp(element, "ig").test(yourString) })) {
        // do something
    }
Адель Мурад
источник
1

Используя 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
BuffMcBigHuge
источник
1

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

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

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

var parameters = ['a','b']
parameters.includes('a')    // true
Линкольн Андерс
источник
1

опираясь на ответ TJ Crowder

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

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
источник
1

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

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

"Альфа" "Бета" "Гамма" "Дельта"

"Альфа Бета" "Бета Гамма" "Гамма Дельта"

"Альфа Бета Гамма" "Бета Гамма Дельта"

"Альфа Бета Гамма Дельта"

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

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

Недостатком является то, что вы не можете искать подстроки, такие как "Ta Gamm". Конечно, вы можете учесть это, разделяя по символам, а не по словам, но тогда вам часто придется создавать массивный сет, и затраченное на это время / память перевешивает преимущества.

Эмиль Норен
источник
1

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

Вы можете проверить так:

<!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>
Давал Сони
источник
-1
let obj = [{name : 'amit'},{name : 'arti'},{name : 'sumit'}];
let input = 'it';

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

obj.filter((n)=> n.name.trim().toLowerCase().includes(input.trim().toLowerCase()))
ArtiSK
источник
Пожалуйста, посетите и проверьте, как ответить на вопрос .
Юнус Темурленк
@YunusTemurlenk thnx
Артиск