Як перевірити, чи містить рядок текст з масиву підрядів у JavaScript?


163

Досить прямо вперед. У JavaScript я повинен перевірити, чи містить рядок якісь підрядки, що містяться в масиві.


Чи немає map()функції в новій версії HTML5-JavaScript? Пам’ятаю, прочитав щось на цю тему ...
Мартін Хеннінгс

@Martin: Добрий момент, не mapтак багато some. someдопоможе, але вам доведеться передати це функції.
TJ Crowder

Відповіді:


222

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

Якщо ви знаєте, що рядки не містять жодного символу, який є спеціальним у регулярних виразах, то ви можете трохи обдурити, як це:

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, хоча це полівіє заповнення.


Оновлення в 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
}

Живий приклад:


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

50

Рішення однієї лінії

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

Повертає, true\falseякщо підрядкаexists\does'nt exist

Потрібна підтримка ES6


Прекрасне рішення за допомогою функцій стрілок
GuerillaRadio

7
Ви, діти, ще коли я був дитиною, нам довелося використовувати ці речі, що називаються циклами "for", і вам довелося використовувати декілька рядків і знати, чи ваш масив базується на 1 або нулі, так ... так, половину часу, коли ви отримали це неправильно, і довелося налагоджувати та шукати маленьку помилку під назвою "я".
амарки

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

Для людей в 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`
}

2
або коротше: якщо (substrings.some (v => v === str)) {
kofifus

10
Зауважте, що це відповідь на дещо інше запитання, яке запитує, чи містить рядок текст із масиву підрядків. Цей код перевіряє , є чи рядок є одним з подстрок. Залежить від того, що мається на увазі "містить", я думаю.
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]
    }
}

редагувати: Якщо порядок тестів не має значення, ви можете використовувати це (лише з однією змінною циклу):

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


2

Спираючись на рішення TJ Crowder, я створив прототип для вирішення цієї проблеми:

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

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

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


1

Якщо ви працюєте з довгим списком підрядків, що складаються з повних "слів", розділених пробілами, або будь-якого іншого загального символу, ви можете бути трохи розумними у своєму пошуку.

Спочатку розділіть рядок на групи X, потім X + 1, потім X + 2, ..., аж до Y. X і Y має бути числом слів у вашій підрядці з найменшою кількістю і самих слів відповідно. Наприклад, якщо X дорівнює 1, а Y - 4, "Alpha Beta Gamma Delta" стає:

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

"Альфа-бета" "Бета-гамма" "Гамма-дельта"

"Alpha Beta Gamma" "Beta Gamma Delta"

"Альфа бета-гамма дельта"

Якщо 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)


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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.