web-dev-qa-db-fra.com

Comment compter l'occurrence de chaîne dans une chaîne?

Comment puis-je compter le nombre de fois qu'une chaîne particulière se produit dans une autre chaîne. Par exemple, voici ce que j'essaie de faire en Javascript:

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

La g dans l'expression régulière (abréviation de global ) indique de rechercher la chaîne entière plutôt que de rechercher la première occurrence. Cela correspond à is deux fois:

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

Et, s'il n'y a pas de correspondance, il retourne 0:

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

831
Rebecca Chernoff
/** 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;
}

Usage

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

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

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

allowOverlapping

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

Allumettes:

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

Test de l'unité

Référence

J'ai fait un test de référence et ma fonction est plus de 10 fois plus vite que la fonction de correspondance regexp postée par gumbo. Dans mon test la chaîne a une longueur de 25 caractères. avec 2 occurrences du caractère 'o'. JE exécuté 1 000 000 fois à Safari.

Safari 5.1

Indicateur de référence> Temps total d'exécution: 5617 ms (expression rationnelle)

Indice de référence> Temps d'exécution total: 881 ms (ma fonction est 6,4 fois plus rapide)

Firefox 4

Indicateur de référence> Temps total d'exécution: 8547 ms (Rexexp)

Indice de référence> Temps d'exécution total: 634 ms (ma fonction est 13.5x plus rapide)


Edit: modifications que j'ai faites

  • longueur de sous-chaîne mise en cache

  • ajout de la saisie de caractères à la chaîne.

  • ajout du paramètre optionnel 'allowOverlapping'

  • correction de la sortie correcte pour "" la casse de sous-chaîne vide.

207
Vitim.us
function countInstances(string, Word) {
   return string.split(Word).length - 1;
}
86
Orbit

Vous pouvez essayer ceci:

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

74
Freezy Ize

Ma solution:

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

32
Gere

Vous pouvez utiliser match pour définir cette fonction:

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

Juste le code-golf Rebecca Chernoff 's solution :-)

alert(("This is a string.".match(/is/g) || []).length);
10
TMS

La version 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

9
Faraz Kelhini

Voici la fonction la plus rapide!

Pourquoi est-ce plus rapide?

  • Ne vérifie pas caractère par caractère (à une exception près)
  • Utilise un moment et incrémente 1 var (le nombre de caractères var) contre une boucle for vérifiant la longueur et incrémentant 2 vars (généralement var i et une var avec le nombre de caractères)
  • Utilise beaucoup moins de vars
  • N'utilise pas de regex!
  • Utilise une fonction (optimalement) hautement optimisée
  • Toutes les opérations sont aussi combinées que possible, en évitant les ralentissements dus aux opérations multiples

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

Voici une version plus lente et plus lisible:

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

Celui-ci est plus lent à cause du compteur, des noms de variables longs et de l'utilisation abusive de 1 var.

Pour l'utiliser, vous faites simplement ceci:

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

Edit: (2013/12/16)

NE PAS utiliser avec Opera 12.16 ou plus ancien! il faudra presque 2,5 fois plus que la solution regex!

Sur chrome, cette solution prendra entre 14 ms et 20 ms pour 1 000 000 de caractères.

La solution regex prend 11-14 ms pour le même montant.

L'utilisation d'une fonction (en dehors de String.prototype) prendra environ 10-13 ms.

Voici le code utilisé:

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

Le résultat de toutes les solutions devrait être de 100 000!

Remarque: si vous voulez que cette fonction compte plus de 1 caractère, changez où est c=(c+'')[0] en c=c+''

8
Ismael Miguel

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

6
Sunil Garg

Je pense que le but de regex est très différent de indexOf.indexOf simplement trouver l'occurrence d'une certaine chaîne alors que dans regex vous pouvez utiliser des jokers comme [A-Z] qui signifie qu'il trouvera toute caractère capital dans le mot sans préciser le caractère réel.

Exemple:

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

4
Simm

String.prototype.Count = function (find) { return this.split(find).length - 1; } "This is a string.".Count("is");

Cela retournera 2.

4
Fad Seck
       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");

Référez-vous: - comptez qu'une sous-chaîne apparaît dans la chaîne pour une explication étape par étape.

3
Ranju

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

Utilisez get_occurrence (varS, string) pour rechercher l'occurrence des caractères et de la chaîne dans une chaîne.

3
Rahul Ranjan

Super duper vieux, mais je devais faire quelque chose comme ça aujourd'hui et ne pensais qu'à vérifier SO après. Ça marche assez vite pour moi.

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
Jason Larke

Si vous trouvez ce fil dans le futur, notez que la réponse acceptée ne renverra pas toujours la valeur correcte si vous la généralisez, car elle gênera les opérateurs regex comme $ et .. Voici une meilleure version, qui peut gérer n'importe quel aiguille:

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

S'appuyant sur @ Vittim.us, répondez ci-dessus. J'aime le contrôle que me donne sa méthode, ce qui facilite son extension, mais je devais ajouter l'insensibilité à la casse et limiter les correspondances à des mots entiers avec prise en charge de la ponctuation. (par exemple, "bain" est en "prendre un bain." mais pas "bain")

La regex de ponctuation provient de: https://stackoverflow.com/a/25575009/497745 ( Comment puis-je enlever toute la ponctuation d'une chaîne en JavaScript en utilisant 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;
}

N'hésitez pas à modifier et à reformuler cette réponse si vous remarquez des bogues ou des améliorations.

3
Ayo I

L'essayer

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

Version simple sans regex:

var temp = "This is a string.";

var count = (temp.split('is').length - 1);

alert(count);

2
Jorge Alberto

C’est un très vieux fil que j’ai rencontré, mais comme beaucoup ont insisté sur leur réponse, voici le mien dans l’espoir d'aider quelqu'un avec ce code simple.

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[letter.length - 1];
var count;
for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));
console.log(count);

Je ne suis pas sûr que ce soit la solution la plus rapide, mais je l’ai préférée pour la simplicité et pour ne pas utiliser regex (je n’aime pas les utiliser!)

1
Tushar Shukla

Réponse pour Leandro Batista: Juste un problème avec l’expression régulière.

 "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
PhilMaGeo

est tombé sur ce message.

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
}

Le même algorithme peut être présenté plus rapidement:

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
Ashok R

Cette solution est basée sur la méthode .replace() qui accepte un RegEx comme premier paramètre et une fonction comme second paramètre que nous pouvons utiliser comme fermeture pour incrémenter un compteur.

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

Usage

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

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

Personne ne le verra jamais, mais il est bon de ramener de temps en temps la récursion et les flèches

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

Un peu tard mais supposons que nous ayons la chaîne suivante:

var temp = "This is a string.";

Tout d’abord, nous divisons ce que vous cherchez, cela retournera un tableau de chaînes.

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

Ensuite, nous obtenons sa longueur et lui soustrayons 1 puisque la division par défaut est un tableau de taille 1 et que, par conséquent, nous incrémentons sa taille chaque fois qu’il trouve une occurrence.

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

Vous pouvez également faire tout cela en une seule ligne comme suit:

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

J'espère que ça aide: D

0

var s = "1";replaced Word
var a = "HRA"; //have to replace 
var str = document.getElementById("test").innerHTML;
var count = str.split(a).length - 1;
for (var i = 0; i < count; i++) {
    var s = "1";
    var a = "HRA";
    var str = document.getElementById("test").innerHTML;
    var res = str.replace(a, s);
    document.getElementById("test").innerHTML = res;
}

<input " type="button" id="Btn_Validate" value="Validate" class="btn btn-info" />
<div class="textarea"  id="test" contenteditable="true">HRABHRA</div>

0
jithin

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
Kamal