Come contare l'occorrenza della stringa nella stringa?


609

Come posso contare il numero di volte in cui una particolare stringa si verifica in un'altra stringa. Ad esempio, questo è quello che sto cercando di fare in Javascript:

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

19
Dipende se si accettano istanze sovrapposte , ad esempio var t = "sss"; Quante istanze della sottostringa "ss" sono nella stringa sopra? 1 o 2? Saltate la rana sopra ogni istanza o spostate il puntatore carattere per carattere, cercando la sottostringa?
Tim

4
Un benchmark migliorato per le risposte a questa domanda: jsperf.com/string-ocurrence-split-vs-match/2 (basato sul benchmark di Kazzkiq).
idmean

Risposte:


1030

L' gespressione regolare (abbreviazione di globale ) dice di cercare l'intera stringa anziché trovare solo la prima occorrenza. Questo corrisponde isdue volte:

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

E, se non ci sono corrispondenze, restituisce 0:

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


3
moderno ed elegante, ma la soluzione di Vitimtk è molto più efficiente. cosa ne pensate tutti del suo codice?
TruMan1

5
Questo risponde meglio alla domanda. Se qualcuno chiedesse "Come posso fare questo 10 volte più veloce in un caso speciale (senza regexps)" Vitimtk vincerebbe quella domanda.
Dzhaughn,

121
Grazie per questo .. Sono andato count = (str.match(/is/g) || []).lengtha gestire se non hai una corrispondenza.
Matt,

6
Non penso che questa risposta corrisponda correttamente alla domanda, perché non ci vuole una stringa come argomento da abbinare, come descrive il caso d'uso. Certo, puoi creare dinamicamente la regexp usando il RegExpcostruttore e passando la stringa che stai cercando, ma in quel caso devi scappare da tutti i metacaratteri. In quello scenario, è preferibile un approccio di stringa pura.
ZER0

3
La risposta di Matt dovrebbe essere nella risposta!
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;
}

uso

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

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

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

allowOverlapping

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

gli incontri:

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

Test unitario

Prova delle prestazioni

Ho fatto un test di benchmark e la mia funzione è più di 10 volte più veloce della funzione regexp match pubblicata da gumbo. Nella mia stringa di test è lunga 25 caratteri. con 2 occorrenze del carattere 'o'. Ho eseguito 1.000.000 di volte in Safari.

Safari 5.1

Benchmark> Esecuzione tempo totale: 5617 ms (regexp)

Benchmark> Esecuzione tempo totale: 881 ms (la mia funzione 6,4 volte più veloce)

Firefox 4

Benchmark> Esecuzione tempo totale: 8547 ms (Rexexp)

Benchmark> Esecuzione tempo totale: 634 ms (la mia funzione 13,5 volte più veloce)


Modifica: modifiche che ho apportato

  • lunghezza della sottostringa memorizzata nella cache

  • aggiunto il casting del tipo alla stringa.

  • aggiunto il parametro opzionale 'allowOverlapping'

  • corretto output corretto per "" custodia per sottostringa vuota

nocciolo

5
Ho ripetuto questo test in Safari 5 e ho ottenuto risultati simili con una stringa piccola (100b), ma con una stringa più grande (16kb), il regex ha funzionato più velocemente per me. Per una ripetizione (non 1.000.000), la differenza era comunque inferiore a un millisecondo, quindi il mio voto va alla regex.
arlomedia,

2
+1, ma stai controllando substring.lengthquasi ogni ciclo, dovresti considerare di memorizzarlo nella cache all'esterno diwhile
ajax333221

1
@ ajax333221 OMG mi hai letto nella mente, ho apportato questo miglioramento qualche giorno fa e stavo per modificare la mia risposta jsperf.com/count-string-occurrence-in-string
Vitim.us

4
Ho trovato il tuo codice in uso qui: success-equation.com/mind_reader.html . Davvero bello il programmatore ha pensato di inserire un riferimento lì.
Bruno Kim,

3
@DanielZuzevich costringerà i tipi a String , in caso affermativo occurrences(11,1) //2e funzionerebbe ancora. (È più veloce in questo modo invece di controllare i tipi e chiamare toString () )
Vitim.us

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

4
Questo è un approccio non sicuro / imprecise, per esempio: countInstances("isisisisisis", "is") === 0.
Nick Craver

5
@Antal - Sembra un bug nella precedente versione beta di Chrome, funziona dopo l'aggiornamento alla versione più recente, comunque mi starei alla larga da questo metodo.
Nick Craver

28
Questa mi sembra una soluzione perfettamente valida.
Gregor Schmidt,

2
@NickCraver per curiosità, perché vuoi evitare questo metodo? (diverso dai bug nel tuo browser beta)
Jonny Lin,

6
@JonnyLin crea allocazioni superflue che butti immediatamente via quando non ci sono alternative - potenzialmente molto grandi a seconda dei dati.
Nick Craver

88

Puoi provare questo:

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


14
+1 per la semplicità e perché in base ai miei test questa soluzione funziona ~ 10 volte più veloce delle altre!
Claudio Holanda,

Ad esempio ho due "è" come si ottiene la posizione di ciascuno?
rapidoodle,

Come discusso nella risposta di @Orbit, le persone stanno ottenendo risultati diversi sulle versioni precedenti di Chrome. Forse sarei un po 'cauto usando questo metodo.
mgthomas99

E puoi anche usarlo con le variabili: theString.split(myvar).length - 1che non puoi con regex semplice
Steffan,

4
Questa è la risposta di @Orbit tre anni dopo ...
aloisdg si trasferisce su codidact.com il

33

La mia soluzione:

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
forse sarebbe meglio restituire (str.match (regExp) || []). length; In questo modo non valuti due volte l'espressione regolare?
aikeru,

2
devi anche scapezzarti la corda o countOcurrences('Hello...','.')==8meno 3
Vitim.us

19

È possibile utilizzare matchper definire tale funzione:

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

1
Se volessi che fosse uniforme con la semantica della ricerca di JS, la linea di ritorno sarebbe return m ? m.length:-1;.
Conor O'Brien,

Questo è meglio delle altre soluzioni regex sopra, perché causano un errore se la stringa per contare le occorrenze di è "[" o qualsiasi cosa con un significato speciale in Regex.
programmatore 5

11

La versione non regex:

 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. È solo per la ricerca di caratteri singoli, troppo sottile 2. anche OP richiede isoccorrenze
vladkras

1
Questa è probabilmente l'implementazione più veloce qui, ma sarebbe ancora più veloce se sostituissi "++ pos" con "pos + = searchFor.length"
hanshenrik



8

Ecco la funzione più veloce!

Perché è più veloce?

  • Non controlla il carattere in base al carattere (con 1 eccezione)
  • Utilizza un po 'di tempo e incrementa 1 var (il var di conteggio dei caratteri) rispetto a un ciclo for che controlla la lunghezza e incrementa 2 var (di solito var i e una var con il conteggio dei caratteri)
  • Usa MODI meno variegati
  • Non usa regex!
  • Utilizza una funzione (si spera) altamente ottimizzata
  • Tutte le operazioni sono combinate il più possibile, evitando rallentamenti dovuti a più operazioni

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

Ecco una versione più lenta e più leggibile:

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

Questo è più lento a causa del contatore, nomi var lunghi e uso improprio di 1 var.

Per usarlo, devi semplicemente fare questo:

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

Modifica: (2013/12/16)

NON utilizzare con Opera 12.16 o precedente! ci vorrà quasi 2,5 volte di più rispetto alla soluzione regex!

Su Chrome, questa soluzione richiederà tra 14 e 20 ms per 1.000.000 di caratteri.

La soluzione regex richiede 11-14ms per la stessa quantità.

L'uso di una funzione (all'esterno String.prototype) richiederà circa 10-13ms.

Ecco il codice utilizzato:

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

Il risultato di tutte le soluzioni dovrebbe essere 100.000!

Nota: se si desidera che questa funzione per contare più di 1 char, cambiamento in cui è c=(c+'')[0]inc=c+''


1
il prototipo era UN ESEMPIO! Puoi usare la funzione come preferisci! Puoi persino farlo: var timesFunctionExist = function (x, c) {var t = 0, l = 0, c = (c + '') [0]; while (l = x.indexOf (c, l) +1 ) ++ t; restituisce t}); alert (timesCharExist ('Il carattere "a" appare solo due volte', 'a')) ;! (questo accelererà un po 'di più perché non farò casino con i prototipi). Se pensi che mi sbagli, perché non lo mostri prima di lanciarmi contro le pietre? Dimostrami che la mia funzione fa schifo e la accetterò. Fammi vedere un caso di prova. E la lunghezza dei var ha influenza sulla velocità. Puoi provarlo.
Ismael Miguel,

7

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


4

Penso che lo scopo di regex sia molto diverso da indexOf. indexOfè sufficiente trovare la presenza di una determinata stringa mentre in regex è possibile utilizzare caratteri jolly come il [A-Z]che significa che ne troverà una carattere maiuscolo nella parola senza dichiarare il carattere reale.

Esempio:

 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

Super duper vecchio, ma dovevo fare qualcosa del genere oggi e ho pensato di controllare SO in seguito. Funziona abbastanza velocemente per me.

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
       var myString = "This is a string.";
        var foundAtPosition = 0;
        var Count = 0;
        while (foundAtPosition != -1)
        {
            foundAtPosition = myString.indexOf("is",foundAtPosition);
            if (foundAtPosition != -1)
            {
                Count++;
                foundAtPosition++;
            }
        }
        document.write("There are " + Count + " occurrences of the word IS");

Consultare: - contare una sottostringa visualizzata nella stringa per una spiegazione dettagliata.


3

Basandosi sulla risposta @ Vittim.us sopra. Mi piace il controllo che il suo metodo mi offre, facilitando l'estensione, ma dovevo aggiungere insensibilità al maiuscolo e limitare le corrispondenze a parole intere con il supporto della punteggiatura. (ad es. "bagno" è "fare il bagno" ma non "fare il bagno")

La regex di punteggiatura proviene da: https://stackoverflow.com/a/25575009/497745 ( Come posso rimuovere tutta la punteggiatura da una stringa in JavaScript usando 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;
}

Non esitare a modificare e riformattare questa risposta se riscontri errori o miglioramenti.


3

Per chiunque trovi questo thread in futuro, nota che la risposta accettata non restituirà sempre il valore corretto se lo generalizzi, poiché soffocerà su operatori regex come $e .. Ecco una versione migliore, in grado di gestire qualsiasi ago:

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

Utilizzare get_occurrence (varS, string) per trovare occorrenze di caratteri e stringhe in una stringa.


2

Provalo

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

Nessuno lo vedrà mai, ma è bene riportare di tanto in tanto le funzioni di ricorsione e freccia (gioco di parole gloriosamente inteso)

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


1

Ora questo è un thread molto vecchio che ho trovato, ma poiché molti hanno spinto la loro risposta, ecco la mia nella speranza di aiutare qualcuno con questo semplice codice.

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

Non sono sicuro che sia la soluzione più veloce ma l'ho preferito per semplicità e per non usare regex (semplicemente non mi piace usarli!)


1

Questa funzione restituisce il numero di occorrenze di una parola nel testo.

Nota che usiamo toLowerCase per calcolare il numero di occorrenze qualunque sia il formato (maiuscolo, maiuscolo ...) della parola e del testo

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

0

Risposta per Leandro Batista: solo un problema con l'espressione regex.

 "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

Un po 'in ritardo ma, supponendo che abbiamo la seguente stringa:

var temp = "This is a string.";

Innanzitutto ci dividiamo su qualunque cosa tu stia cercando di abbinare, questo restituirà una serie di stringhe.

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

Quindi ne ricaviamo la lunghezza e sottraggiamo 1 da esso poiché la divisione dei valori predefiniti in un array di dimensioni 1 e di conseguenza aumenta le sue dimensioni ogni volta che trova un'occorrenza.

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

Puoi anche fare tutto questo in una riga come segue:

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

Spero che sia d'aiuto: D


1
Posso contrassegnare questo come una risposta duplicata? Forse dovresti leggere tutte le risposte prima di fornirne una tua?
Michiel,

2
Questa è la risposta di @Orbit otto anni dopo ...
aloisdg si trasferisce su codidact.com il

1
Devo eliminare questa risposta allora?
Juan Enrique Segebre,

0

Questa soluzione si basa sul .replace() metodo che accetta un RegEx come primo parametro e una funzione come secondo parametro che possiamo usare come chiusura per incrementare un contatore ...

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

uso

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

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

0

mi sono imbattuto in questo post.

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
}

Lo stesso algoritmo può essere strutturato in modo più breve:

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 tradotto in Javascript da 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
}

Scopri la traduzione di Locutus della funzione substr_count di Php


-2

Prova questo:

function countString(str, search){
    var count=0;
    var index=str.indexOf(search);
    while(index!=-1){
        count++;
        index=str.indexOf(search,index+1);
    }
    return count;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.