Як порахувати появу рядка в рядку?


607

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

var temp = "This is a string.";
alert(temp.count("is")); //should output '2'

19
Це залежить від того, чи приймаєте ви екземпляри, що перекриваються , наприклад var t = "sss"; Скільки примірників підрядків "ss" є в рядку вище? 1 або 2? Ви перестрибуєте через кожен екземпляр чи переміщуєте вказівник символ за символом, шукаючи підрядку?
Тім

4
Вдосконалений орієнтир для відповідей на це питання: jsperf.com/string-ocurrence-split-vs-match/2 (на основі еталону Kazzkiq).
idmean

Відповіді:


1028

У gрегулярному виразі (короткий для глобального ) сказано, щоб шукати весь рядок, а не просто знаходити перше явище. Це збігається isдвічі:

var temp = "This is a string.";
var count = (temp.match(/is/g) || []).length;
console.log(count);

І якщо немає відповідностей, він повертається 0:

var temp = "Hello World!";
var count = (temp.match(/is/g) || []).length;
console.log(count);


3
сучасне та елегантне, але рішення Вітимтка набагато ефективніше. що ви всі думаєте про його код?
TruMan1

5
Це найкраще відповідає на питання. Якби хтось запитав "Як я можу зробити це в 10 разів швидше у спеціальному випадку (без регулярних виразів)", Vitimtk виграв би це питання.
Джаун

121
Дякую за це .. Я пішов з count = (str.match(/is/g) || []).lengthцим, якщо у вас немає відповідності.
Метт

6
Я не думаю, що ця відповідь відповідає питанням належним чином, оскільки вона не бере рядок як аргумент, як описує випадок використання. Звичайно, ви можете динамічно створювати регулярний вираз за допомогою RegExpконструктора і передаючи шукану рядок, але в цьому випадку вам доведеться уникати всіх метахарактерів. У такому сценарії кращим є струнний підхід.
ZER0

3
У відповіді має бути відповідь Метта!
Senči

240
/** Function that count occurrences of a substring in a string;
 * @param {String} string               The string
 * @param {String} subString            The sub string to search for
 * @param {Boolean} [allowOverlapping]  Optional. (Default:false)
 *
 * @author Vitim.us https://gist.github.com/victornpb/7736865
 * @see Unit Test https://jsfiddle.net/Victornpb/5axuh96u/
 * @see http://stackoverflow.com/questions/4009756/how-to-count-string-occurrence-in-string/7924240#7924240
 */
function occurrences(string, subString, allowOverlapping) {

    string += "";
    subString += "";
    if (subString.length <= 0) return (string.length + 1);

    var n = 0,
        pos = 0,
        step = allowOverlapping ? 1 : subString.length;

    while (true) {
        pos = string.indexOf(subString, pos);
        if (pos >= 0) {
            ++n;
            pos += step;
        } else break;
    }
    return n;
}

Використання

occurrences("foofoofoo", "bar"); //0

occurrences("foofoofoo", "foo"); //3

occurrences("foofoofoo", "foofoo"); //1

дозволити перекриття

occurrences("foofoofoo", "foofoo", true); //2

Матчі:

  foofoofoo
1 `----´
2    `----´

Тест одиниці

Орієнтир

Я зробив контрольний тест, і моя функція більш ніж в 10 разів швидша, ніж функція відповідності регулярного вирівнювання, розміщена gumbo. У моєму тестовому рядку довжина 25 символів. з двома випадками символу «о». Я стратив 1 000 000 разів у Safari.

Сафарі 5.1

Тест> Загальний час виконання: 5617 мс (regexp)

Тест> Загальний час виконання: 881 мс (моя функція на 6,4 рази швидша)

Firefox 4

Тест> Загальний час виконання: 8547 мс (Rexexp)

Тест> Загальний час виконання: 634 мс (моя функція на 13,5 разів швидше)


Редагувати: зміни, які я внесла

  • довжина кешованої підрядки

  • додано кастинг типу в рядок.

  • додано необов'язковий параметр "enableOverlapping"

  • фіксований правильний вихід для "" порожнього рядка підрядки.

Суть

5
Я повторив цей тест в Safari 5 і отримав подібні результати з невеликою (100b) струною, але з більшою струною (16kb), регулярний вислів біг швидше для мене. За одну ітерацію (не 1 мільйон) різниця була менше мілісекунди, так що мій голос іде на регулярний вираз.
arlomedia

2
+1, але ви перевіряєте substring.lengthмайже кожен цикл, вам слід розглянути можливість кешування його позаwhile
ajax333221

1
@ ajax333221 OMG Ви читаєте, що я міг змінити, я зробив це вдосконалення кілька днів тому, і я збирався редагувати свою відповідь jsperf.com/count-string-occurrence-in-string
Vitim.us

4
Я знайшов ваш код, який тут використовується: success-equation.com/mind_reader.html . Дійсно приємно, що програміст подумав поставити там посилання.
Бруно Кім

3
@DanielZuzevich це буде примушувати типи до String , якщо ви зробите occurrences(11,1) //2це, і воно все одно спрацює. (Швидше це робити замість перевірки типів та виклику toString () )
Vitim.us

112
function countInstances(string, word) {
   return string.split(word).length - 1;
}

4
Це небезпечний / неточний підхід, наприклад: countInstances("isisisisisis", "is") === 0.
Нік Крейвер

5
@Antal - Виглядає як помилка в попередній бета-версії хрому, працює після оновлення до останнього, я все-таки уникаю цього методу.
Нік Крейвер

28
Це виглядає як ідеально для мене рішення.
Грегор Шмідт

2
@NickCraver з цікавості, чому ви хочете уникати цього методу? (крім помилки у вашому бета-браузері)
Jonny Lin

6
@JonnyLin це створює непотрібні виділення, які ви негайно викидаєте, коли альтернативи не мають - потенційно дуже великі, залежно від даних.
Нік Крейвер

88

Ви можете спробувати це:

var theString = "This is a string.";
console.log(theString.split("is").length - 1);


14
+1 для простоти, і тому, відповідно до моїх тестів, це рішення працює на 10 разів швидше, ніж інші!
Клаудіо Голландія

Наприклад, у мене є два "є", як ти займаєш позицію кожного?
fastoodle

Як обговорюється у відповіді @Orbit, люди отримують різні результати на старих версіях Chrome. Я, можливо, буду трохи обережним, використовуючи цей метод.
mgthomas99

І ви також можете використовувати його зі змінними: theString.split(myvar).length - 1що ви не можете з простим регулярним виразом
Steffan

4
Це @Orbit «сек відповідь через три роки ...
aloisdg переїзд в codidact.com

33

Моє рішення:

var temp = "This is a string.";

function countOcurrences(str, value) {
  var regExp = new RegExp(value, "gi");
  return (str.match(regExp) || []).length;
}

console.log(countOcurrences(temp, 'is'));


5
можливо, було б краще повернути (str.match (regExp) || []). length; Таким чином, ви не оцінюєте регулярний вираз двічі?
aikeru

2
вам також потрібно скапати вашу струну чи countOcurrences('Hello...','.')==8не, а не 3
Vitim.us

19

Ви можете використовувати matchдля визначення такої функції:

String.prototype.count = function(search) {
    var m = this.match(new RegExp(search.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "g"));
    return m ? m.length:0;
}

1
Якби ви хотіли, щоб вона була рівномірною з пошуковою семантикою JS, повернення було б return m ? m.length:-1; .
Conor O'Brien

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

11

Версія, що не повторюється:

 var string = 'This is a string',
    searchFor = 'is',
    count = 0,
    pos = string.indexOf(searchFor);

while (pos > -1) {
    ++count;
    pos = string.indexOf(searchFor, ++pos);
}

console.log(count);   // 2


1. Це лише для пошуку одного чару, занадто тонкого 2. навіть ОП просить isвиникнення
випадків

1
Це, мабуть, найшвидша реалізація тут, але це було б ще швидше, якби ви замінили "++ pos" на "pos + = searchFor.length"
hanshenrik,



8

Ось найшвидша функція!

Чому це швидше?

  • Не перевіряє char за статусом char (за винятком 1)
  • Використовує час та збільшує 1 var (char count var) vs. a для циклу, що перевіряє довжину та збільшує 2 vars (зазвичай var i та var з count char)
  • ВИКОРИСТАННЯ ШЛЯХО менше вар
  • Не використовує регулярний вираз!
  • Використовує (сподіваємось), оптимізовану функцію
  • Усі операції є настільки ж комбінованими, як вони можуть бути, уникаючи уповільнень через кілька операцій

    String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};

Ось більш повільна і читабельна версія:

    String.prototype.timesCharExist = function ( chr ) {
        var total = 0, last_location = 0, single_char = ( chr + '' )[0];
        while( last_location = this.indexOf( single_char, last_location ) + 1 )
        {
            total = total + 1;
        }
        return total;
    };

Це повільніше через лічильник, довгі назви вар та неправильне використання 1 вар.

Щоб скористатися ним, ви просто зробите це:

    'The char "a" only shows up twice'.timesCharExist('a');

Редагувати: (2013/12/16)

НЕ використовуйте з Opera 12.16 або старші! знадобиться майже в 2,5 рази більше, ніж розчин регексу!

Що стосується хрому, це рішення займе від 14 мс до 20 мс для 1 000 000 символів.

Розчин регулярного гекса займає 11-14 мс на стільки ж.

Використання функції (зовні String.prototype) займе приблизно 10-13 мс.

Ось використаний код:

    String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};

    var x=Array(100001).join('1234567890');

    console.time('proto');x.timesCharExist('1');console.timeEnd('proto');

    console.time('regex');x.match(/1/g).length;console.timeEnd('regex');

    var timesCharExist=function(x,c){var t=0,l=0,c=(c+'')[0];while(l=x.indexOf(c,l)+1)++t;return t;};

    console.time('func');timesCharExist(x,'1');console.timeEnd('func');

Результат усіх рішень повинен бути 100 000!

Примітка: якщо ви хочете , щоб ця функція нарахувати більше 1 символ, зміна де c=(c+'')[0]вc=c+''


1
прототипом був ПРИКЛАД! Ви можете використовувати функцію як завгодно! Ви навіть можете це зробити: var timesFunctionExist = функція (x, c) {var t = 0, l = 0, c = (c + '') [0]; while (l = x.indexOf (c, l) +1 ) ++ t; повернути t}); alert (timesCharExist ('Char' a "відображається лише двічі ',' a ')); (це пришвидшить трохи більше, тому що я не буду возитися з прототипами). Якщо ви думаєте, що я помиляюся, чому б вам не показати цього, перш ніж кидати мені скелі? Доведіть мені, що моя функція відстійна, і я прийму її. Покажіть мені тестовий випадок. А довжина вар впливає на швидкість. Ви можете протестувати.
Ісмаїл Мігель


4

Я думаю, що призначення регексу сильно відрізняється від indexOf. indexOfпросто знайдіть виникнення певного рядка, тоді як у регулярному вираженні ви можете використовувати подвійні символи типу[A-Z] це означає, що він знайде будь-який головний символ у слові без зазначення фактичного символу.

Приклад:

 var index = "This is a string".indexOf("is");
 console.log(index);
 var length = "This is a string".match(/[a-z]/g).length;
 // where [a-z] is a regex wildcard expression thats why its slower
 console.log(length);


3

Супер пупер старий, але мені потрібно було зробити щось подібне сьогодні і тільки думав перевірити ТАК після цього. Для мене працює досить швидко.

String.prototype.count = function(substr,start,overlap) {
    overlap = overlap || false;
    start = start || 0;

    var count = 0, 
        offset = overlap ? 1 : substr.length;

    while((start = this.indexOf(substr, start) + offset) !== (offset - 1))
        ++count;
    return count;
};


3

На основі відповіді на @ Vittim.us вище. Мені подобається контроль, який надає мені його метод, що дозволяє легко розширити, але мені потрібно було додати нечутливість регістру та обмежити відповідність цілим словам з підтримкою пунктуації. (наприклад, "ванна" - це "прийняти ванну", але не "купання")

Регекс пунктуації походить від: https://stackoverflow.com/a/25575009/497745 ( Як я можу викреслити всі розділові знаки з рядка в JavaScript за допомогою regex? )

function keywordOccurrences(string, subString, allowOverlapping, caseInsensitive, wholeWord)
{

    string += "";
    subString += "";
    if (subString.length <= 0) return (string.length + 1); //deal with empty strings

    if(caseInsensitive)
    {            
        string = string.toLowerCase();
        subString = subString.toLowerCase();
    }

    var n = 0,
        pos = 0,
        step = allowOverlapping ? 1 : subString.length,
        stringLength = string.length,
        subStringLength = subString.length;

    while (true)
    {
        pos = string.indexOf(subString, pos);
        if (pos >= 0)
        {
            var matchPos = pos;
            pos += step; //slide forward the position pointer no matter what

            if(wholeWord) //only whole word matches are desired
            {
                if(matchPos > 0) //if the string is not at the very beginning we need to check if the previous character is whitespace
                {                        
                    if(!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchPos - 1])) //ignore punctuation
                    {
                        continue; //then this is not a match
                    }
                }

                var matchEnd = matchPos + subStringLength;
                if(matchEnd < stringLength - 1)
                {                        
                    if (!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchEnd])) //ignore punctuation
                    {
                        continue; //then this is not a match
                    }
                }
            }

            ++n;                
        } else break;
    }
    return n;
}

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


3

Для всіх, хто знайде цю тему в майбутньому, зауважте, що прийнята відповідь не завжди поверне правильне значення, якщо ви узагальнюєте її, оскільки вона задихатиметься від операторів регулярних виразів, як $і .. Ось краща версія, яка може обробляти будь-яку голку:

function occurrences (haystack, needle) {
  var _needle = needle
    .replace(/\[/g, '\\[')
    .replace(/\]/g, '\\]')
  return (
    haystack.match(new RegExp('[' + _needle + ']', 'g')) || []
  ).length
}

3

function get_occurrence(varS,string){//Find All Occurrences
        c=(string.split(varS).length - 1);
        return c;
    }
    temp="This is a string.";
    console.log("Total Occurrence is "+get_occurrence("is",temp));

Використовуйте get_occurrence (varS, string), щоб знайти виникнення обох символів і рядка в рядку.


2

Спробуй це

<?php 
$str = "33,33,56,89,56,56";
echo substr_count($str, '56');
?>

<script type="text/javascript">
var temp = "33,33,56,89,56,56";
var count = temp.match(/56/g);  
alert(count.length);
</script>


2

Ніхто цього ніколи не побачить, але добре час від часу повертати функції рекурсії та стрілки (каламбур славно призначений)

String.prototype.occurrencesOf = function(s, i) {
 return (n => (n === -1) ? 0 : 1 + this.occurrencesOf(s, n + 1))(this.indexOf(s, (i || 0)));
};


1

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

var search_value = "This is a dummy sentence!";
var letter = 'a'; /*Can take any letter, have put in a var if anyone wants to use this variable dynamically*/
letter = letter && "string" === typeof letter ? letter : "";
var count;
for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));
console.log(count);

Я не впевнений, чи це найшвидше рішення, але я віддав перевагу цьому для простоти і не для використання регулярного виразу (я просто не люблю їх використовувати!)


1

Ця функція повертає кількість зустрічань слова в тексті.

Зауважте, ми використовуємо toLowerCase для обчислення кількості подій незалежно від формату (великої літери, великого регістру ...) слова та тексту

wordCount(text, word) {
    if (!text || !word) {
      return 0;
    }
    text = text.toLowerCase();
    word = word.toLowerCase();
    return ( text.split( word ).length - 1 );
}

0

Відповідь Леандро Батіста: просто проблема з виразом регулярного вираження.

 "use strict";
 var dataFromDB = "testal";
 
  $('input[name="tbInput"]').on("change",function(){
	var charToTest = $(this).val();
	var howManyChars = charToTest.length;
	var nrMatches = 0;
	if(howManyChars !== 0){
		charToTest = charToTest.charAt(0);
		var regexp = new RegExp(charToTest,'gi');
		var arrMatches = dataFromDB.match(regexp);
		nrMatches = arrMatches ? arrMatches.length : 0;
	}
		$('#result').html(nrMatches.toString());

  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
What do you wanna count <input type="text" name="tbInput" value=""><br />
Number of occurences = <span id="result">0</span>
</div>


0

var countInstances = function(body, target) {
  var globalcounter = 0;
  var concatstring  = '';
  for(var i=0,j=target.length;i<body.length;i++){
    concatstring = body.substring(i-1,j);
    
    if(concatstring === target){
       globalcounter += 1;
       concatstring = '';
    }
  }
  
  
  return globalcounter;
 
};

console.log(   countInstances('abcabc', 'abc')   ); // ==> 2
console.log(   countInstances('ababa', 'aba')   ); // ==> 2
console.log(   countInstances('aaabbb', 'ab')   ); // ==> 1


0

Трохи запізнюємось, але, припускаючи, що у нас є такий рядок:

var temp = "This is a string.";

Спочатку ми розділимо все, що ви шукаєте, щоб відповідати, це поверне масив рядків.

var array = temp.split("is");

Тоді ми отримуємо його довжину і віднімаємо 1 до неї, оскільки розділимо за замовчуванням масив розміром 1 і, як наслідок, збільшуємо його розмір кожного разу, коли він виявляє виникнення.

var occurrenceCount = array.length - 1;
alert(occurrenceCount); //should output '2'

Ви також можете зробити все це в один рядок наступним чином:

alert("This is a string.".split("is").length - 1); //should output '2'

Сподіваюся, що це допомагає: D


1
Чи можу я позначити це як повторювану відповідь? Можливо, ви повинні прочитати всі відповіді, перш ніж надавати свої власні?
Міхель

2
Це @Orbit «сек відповідь вісім років по тому ...
aloisdg переїзд в codidact.com

1
Чи потрібно потім видалити цю відповідь?
Хуан Енріке Сегебре

0

Це рішення засноване на .replace()методі, який приймає RegEx як перший параметр, а функцію як другий параметр, який ми можемо використовувати як закриття для збільшення лічильника ...

/**
 * Return the frequency of a substring in a string
 * @param {string} string - The string.
 * @param {string} string - The substring to count.
 * @returns {number} number - The frequency.
 * 
 * @author Drozerah https://gist.github.com/Drozerah/2b8e08d28413d66c3e63d7fce80994ce
 * @see https://stackoverflow.com/a/55670859/9370788
 */
const subStringCounter = (string, subString) => {

    let count = 0
    string.replace(new RegExp(subString, 'gi'), () => count++)
    return count
}

Використання

subStringCounter("foofoofoo", "bar"); //0

subStringCounter("foofoofoo", "foo"); //3

0

натрапив на цю посаду.

let str = 'As sly as a fox, as strong as an ox';

let target = 'as'; // let's look for it

let pos = 0;
while (true) {
  let foundPos = str.indexOf(target, pos);
  if (foundPos == -1) break;

  alert( `Found at ${foundPos}` );
  pos = foundPos + 1; // continue the search from the next position
}

Один і той же алгоритм можна викласти коротше:

let str = "As sly as a fox, as strong as an ox";
let target = "as";

let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
  alert( pos );
}

0

substr_count перекладено на Javascript з php


function substr_count (haystack, needle, offset, length) { 
  // eslint-disable-line camelcase
  //  discuss at: https://locutus.io/php/substr_count/
  // original by: Kevin van Zonneveld (https://kvz.io)
  // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
  // improved by: Brett Zamir (https://brett-zamir.me)
  // improved by: Thomas
  //   example 1: substr_count('Kevin van Zonneveld', 'e')
  //   returns 1: 3
  //   example 2: substr_count('Kevin van Zonneveld', 'K', 1)
  //   returns 2: 0
  //   example 3: substr_count('Kevin van Zonneveld', 'Z', 0, 10)
  //   returns 3: false

  var cnt = 0

  haystack += ''
  needle += ''
  if (isNaN(offset)) {
    offset = 0
  }
  if (isNaN(length)) {
    length = 0
  }
  if (needle.length === 0) {
    return false
  }
  offset--

  while ((offset = haystack.indexOf(needle, offset + 1)) !== -1) {
    if (length > 0 && (offset + needle.length) > length) {
      return false
    }
    cnt++
  }

  return cnt
}

Ознайомтеся з функцією перекладу Phut's substr_count на переклад Locutus


-2

Спробуйте це:

function countString(str, search){
    var count=0;
    var index=str.indexOf(search);
    while(index!=-1){
        count++;
        index=str.indexOf(search,index+1);
    }
    return count;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.