web-dev-qa-db-fra.com

Compter le nombre d'occurrences d'un caractère dans une chaîne en Javascript

Je dois compter le nombre d'occurrences d'un caractère dans une chaîne.

Par exemple, supposons que ma chaîne contienne:

var mainStr = "str1,str2,str3,str4";

Je veux trouver le nombre de virgules ,, qui est 3. Et le nombre de chaînes individuelles après la division par virgule, qui est 4.

Je dois également valider que chacune des chaînes, à savoir str1, str2, str3 ou str4, ne doit pas dépasser 15 caractères.

403
Akash

J'ai mis à jour cette réponse. J'aime mieux l'idée d'utiliser un match, mais c'est plus lent:

console.log(("str1,str2,str3,str4".match(/,/g) || []).length); //logs 3

console.log(("str1,str2,str3,str4".match(new RegExp("str", "g")) || []).length); //logs 4

jsfiddle

Utilisez un littéral d'expression régulière si vous savez ce que vous recherchez auparavant. Sinon, vous pouvez utiliser le constructeur RegExp et transmettre l'indicateur g en tant qu'argument.

match renvoie null sans résultat, ainsi le || []

La réponse originale que j'ai faite en 2009 est ci-dessous. Cela crée un tableau inutilement, mais utiliser une scission est plus rapide (à partir de septembre 2014). Je suis ambivalent, si j'avais vraiment besoin de la vitesse, il ne ferait aucun doute que j'utiliserais un split, mais je préférerais utiliser le match.

Ancienne réponse (à partir de 2009):

Si vous recherchez les virgules:

(mainStr.split(",").length - 1) //3

Si vous cherchez le str

(mainStr.split("str").length - 1) //4

À la fois dans la réponse de @ Lo et dans mon propre test de jsperf idiot, le fractionnement avance rapidement, du moins sous Chrome, mais créer de nouveau le tableau supplémentaire ne semble tout simplement pas sain d'esprit.

599
Bjorn Tipling

Il y a au moins quatre façons. La meilleure option, qui devrait également être la plus rapide (avec le moteur RegEx natif), est placée en haut. jsperf.com est actuellement en panne, sinon je vous fournirais des statistiques de performance.

Update: Veuillez trouver les tests de performance ici et les exécuter vous-mêmes, de manière à contribuer à vos résultats. Les détails des résultats seront donnés plus tard.

1.

 ("this is foo bar".match(/o/g)||[]).length
 //>2

2.

"this is foo bar".split("o").length-1
 //>2

split non recommandé. Ressources affamées. Alloue de nouvelles instances de 'Array' pour chaque match. N'essayez pas cela pour un fichier> 100 Mo via FileReader. En fait, vous pouvez facilement observer l'utilisation des ressources EXACT à l'aide de l'option profileur de Chrome.

3.

var stringsearch = "o"
   ,str = "this is foo bar";
for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(stringsearch,index+1) );
 //>count:2

4.

recherche d'un seul caractère

var stringsearch = "o"
   ,str = "this is foo bar";
for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++]));
 //>count:2

Mettre à jour:

5.

la cartographie et le filtrage des éléments, non recommandés en raison de la préallocation globale de leurs ressources plutôt que de l'utilisation de «générateurs» Pythonian

var str = "this is foo bar"
str.split('').map( function(e,i){ if(e === 'o') return i;} )
             .filter(Boolean)
//>[9, 10]
[9, 10].length
//>2

(Share:} _ J'ai créé ceci Gist, avec actuellement 8 méthodes de décompte des caractères, afin que nous puissions partager et partager nos idées directement - pour le plaisir, et peut-être même quelques-unes repères intéressants :)

https://Gist.github.com/2757250

178
Lorenz Lo Sauer

Ajoutez cette fonction au prototype Sting:

String.prototype.count=function(c) { 
  var result = 0, i = 0;
  for(i;i<this.length;i++)if(this[i]==c)result++;
  return result;
};

usage:

console.log("strings".count("s")); //2
16
user669677

Un rapide Google search a obtenu ceci (de http://www.codecodex.com/wiki/index.php?title=Count_the_number_of_occurrences_of_a_specific_character_in_a_string#JavaScript )

String.prototype.count=function(s1) { 
    return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}

Utilisez-le comme ceci:

test = 'one,two,three,four'
commas = test.count(',') // returns 3
9
immibis

J'ai constaté que la meilleure approche pour rechercher un caractère dans une très grande chaîne (1 000 000 caractères, par exemple) consiste à utiliser la méthode replace().

window.count_replace = function (str, schar) {
    return str.length - str.replace(RegExp(schar), '').length;
};

Vous pouvez voir encore une autre suite JSPerf pour tester cette méthode ainsi que d’autres méthodes de recherche d’un caractère dans une chaîne.

5
Valera Rozuvan

ok, un autre avec regexp - probablement pas rapide, mais plus lisible que d’autres, dans mon cas, '_' compter

key.replace(/[^_]/g,'').length

supprimez simplement tout ce qui ne ressemble pas à votre personnage mais il ne semble pas agréable avec une chaîne en tant qu'entrée

4
halfbit

Performance de Split vs RegExp

var i = 0;

var split_start = new Date().getTime();
while (i < 30000) {
  "1234,453,123,324".split(",").length -1;
  i++;
}
var split_end = new Date().getTime();
var split_time = split_end - split_start;


i= 0;
var reg_start = new Date().getTime();
while (i < 30000) {
  ("1234,453,123,324".match(/,/g) || []).length;
  i++;
}
var reg_end = new Date().getTime();
var reg_time = reg_end - reg_start;

alert ('Split Execution time: ' + split_time + "\n" + 'RegExp Execution time: ' + reg_time + "\n");

4
Clive Paterson

J'ai apporté une légère amélioration à la réponse acceptée, cela permet de vérifier avec une correspondance sensible à la casse/insensible à la casse et constitue une méthode attachée à l'objet chaîne:

String.prototype.count = function(lit, cis) {
    var m = this.toString().match(new RegExp(lit, ((cis) ? "gi" : "g")));
    return (m != null) ? m.length : 0;
}

lit est la chaîne à rechercher (telle que 'ex'), et cis est insensible à la casse, par défaut à false, il permettra le choix de correspondances insensibles à la casse .


Pour rechercher dans la chaîne 'I love StackOverflow.com' la lettre minuscule 'o', vous devez utiliser:

var amount_of_os = 'I love StackOverflow.com'.count('o');

amount_of_os serait égal à 2.


Si nous recherchions à nouveau la même chaîne en utilisant une correspondance ne respectant pas la casse, vous utiliseriez:

var amount_of_os = 'I love StackOverflow.com'.count('o', true);

Cette fois, amount_of_os serait égal à 3, car la majuscule O de la chaîne est incluse dans la recherche.

3
Dendromaniac

Je travaillais sur un petit projet nécessitant un compteur de sous-chaînes. La recherche des mauvaises phrases ne m'a donné aucun résultat. Cependant, après avoir écrit ma propre implémentation, je suis tombé sur cette question. Quoi qu'il en soit, voici mon chemin, il est probablement plus lent que la plupart des gens ici, mais pourrait être utile à quelqu'un:

function count_letters() {
var counter = 0;

for (var i = 0; i < input.length; i++) {
    var index_of_sub = input.indexOf(input_letter, i);

    if (index_of_sub > -1) {
        counter++;
        i = index_of_sub;
    }
}

http://jsfiddle.net/5ZzHt/1/

S'il vous plaît laissez-moi savoir si vous trouvez cette mise en œuvre à échouer ou ne pas suivre certaines normes! :)

UPDATE Vous voudrez peut-être remplacer:

    for (var i = 0; i < input.length; i++) {

Avec:

for (var i = 0, input_length = input.length; i < input_length; i++) {

Intéressant lu en discutant de ce qui précède: http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value

3
Jakub Wawszczyk

Voici une solution similaire, mais il utilise réduire 

function countCharacters(char, string) {
  return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0)
}

Comme cela a été mentionné, la division est beaucoup plus rapide que le remplacement.

3
uladzimir

Le moyen le plus simple que j'ai découvert ...

Exemple-

str = 'mississippi';

function find_occurences(str, char_to_count){
    return str.split(char_to_count).length - 1;
}

find_occurences(str, 'i') //outputs 4
3
Ankur Choraywal

Si vous utilisez lodash, la méthode _.countBy fera ceci:

_.countBy("abcda")['a'] //2

Cette méthode fonctionne aussi avec array:

_.countBy(['ab', 'cd', 'ab'])['ab'] //2
2
Geng Jiawen

J'utilise Node.js v.6.0.0 et le plus rapide est celui avec index (la troisième méthode dans la réponse de Lo Sauer).

La seconde est:

function count(s, c) {
  var n = 0;
  for (let x of s) {
    if (x == c)
      n++;
  }
  return n;
}

1
Marc K.

Qu'en est-il de string.split (Caractère souhaité) .length-1

Exemple:

var str = "bonjour comment va la vie"; var len = str.split ("h"). length-1; donnera le compte 2 pour le caractère "h" dans la chaîne ci-dessus;

1
user2296195

Ce qui suit utilise une expression régulière pour tester la longueur. testex garantit que vous n'avez pas 16 caractères consécutifs, ou plus, sans virgule. S'il réussit le test, il divise ensuite la chaîne. compter les virgules est aussi simple que compter les jetons moins un.

var mainStr = "str1,str2,str3,str4";
var testregex = /([^,]{16,})/g;
if (testregex.test(mainStr)) {
  alert("values must be separated by commas and each may not exceed 15 characters");
} else {
  var strs = mainStr.split(',');
  alert("mainStr contains " + strs.length + " substrings separated by commas.");
  alert("mainStr contains " + (strs.length-1) + " commas.");
}
1

Vous pouvez également reposer votre chaîne et la manipuler comme un tableau d’éléments utilisant

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].filter(l => l === ',').length;

console.log(commas);

Ou 

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0);

console.log(commas);

1
Yosvel Quintero

Voici une méthode presque aussi rapide que les méthodes split et replace, qui sont un peu plus rapides que la méthode regex (en chrome).

var num = 0;
for (ch of "str1,str2,str3,str4")
{
    if (ch === ',') num++;
}
1
Gerard ONeill
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++
1
wlf

Et voici:

function character_count(string, char, ptr = 0, count = 0) {
    while (ptr = string.indexOf(char, ptr) + 1) {count ++}
    return count
}

Fonctionne aussi avec des nombres entiers!

1
Damion Dooley

Ma solution:

function countOcurrences(str, value){
   var regExp = new RegExp(value, "gi");
   return str.match(regExp) ? str.match(regExp).length : 0;  
}
0
Gere
var a = "acvbasbb";
var b= {};
for (let i=0;i<a.length;i++){
    if((a.match(new RegExp(a[i], "g"))).length > 1){
        b[a[i]]=(a.match(new RegExp(a[i], "g"))).length;
    }
}
console.log(b);

En javascript, vous pouvez utiliser le code ci-dessus pour obtenir l'occurrence d'un caractère dans une chaîne. 

0
Nitin Tyagi

Je sais que cela pourrait être une vieille question, mais j’ai une solution simple pour les débutants de bas niveau en JavaScript. 

En tant que débutant, je ne pouvais comprendre que certaines des solutions à cette question. J'ai donc utilisé deux boucles imbriquées POUR pour comparer chaque caractère par rapport à un autre caractère de la chaîne, en incrémentant une variable count pour chaque. personnage trouvé qui est égal à ce personnage.

J'ai créé un nouvel objet vierge dans lequel chaque clé de propriété est un caractère et la valeur correspond au nombre de fois que chaque caractère est apparu dans la chaîne (nombre).

Exemple de fonction: -

function countAllCharacters(str) {
  var obj = {};
  if(str.length!==0){
    for(i=0;i<str.length;i++){
      var count = 0;
      for(j=0;j<str.length;j++){
        if(str[i] === str[j]){
          count++;
        }
      }
      if(!obj.hasOwnProperty(str[i])){
        obj[str[i]] = count;
      }
    }
  }
  return obj;
}
0
Viscount Wathika

La fonction prend string str comme paramètre et compte l'occurrence de chaque caractère unique dans la chaîne. Le résultat est présenté par paire clé/valeur pour chaque caractère.

var charFoundMap = {};//object defined
    for (var i = 0; i < str.length; i++) {

       if(!charFoundMap[ str[i] ])  {
        charFoundMap[ str[i] ]=1;
       } 
       else
       charFoundMap[ str[i] ] +=1;
       //if object does not contain this 
    }
    return charFoundMap;

} 
0
Pratibha Singh

Je viens de faire un test très rapide et sale sur repl.it en utilisant Node v7.4. Pour un seul caractère, la norme pour la boucle est la plus rapide:

Quelques codes:

// winner!
function charCount1(s, c) {
    let count = 0;
    c = c.charAt(0); // we save some time here
    for(let i = 0; i < s.length; ++i) {
        if(c === s.charAt(i)) {
            ++count;
        }
    }
    return count;
}

function charCount2(s, c) {
    return (s.match(new RegExp(c[0], 'g')) || []).length;
}

function charCount3(s, c) {
    let count = 0;
    for(ch of s) {
        if(c === ch) {
            ++count;
        }
    }
    return count;
}

function perfIt() {
    const s = 'Hello, World!';
    const c = 'o';

    console.time('charCount1');
    for(let i = 0; i < 10000; i++) {
        charCount1(s, c);
    }
    console.timeEnd('charCount1');

    console.time('charCount2');
    for(let i = 0; i < 10000; i++) {
        charCount2(s, c);
    }
    console.timeEnd('charCount2');

    console.time('charCount3');
    for(let i = 0; i < 10000; i++) {
        charCount2(s, c);
    }
    console.timeEnd('charCount3');
}

Résultats de quelques essais:

 perfIt()
charCount1: 3.843ms
charCount2: 11.614ms
charCount3: 11.470ms
=> undefined
   perfIt()
charCount1: 3.006ms
charCount2: 8.193ms
charCount3: 7.941ms
=> undefined
   perfIt()
charCount1: 2.539ms
charCount2: 7.496ms
charCount3: 7.601ms
=> undefined
   perfIt()
charCount1: 2.654ms
charCount2: 7.540ms
charCount3: 7.424ms
=> undefined
   perfIt()
charCount1: 2.950ms
charCount2: 9.445ms
charCount3: 8.589ms
0
NuSkooler

La cinquième méthode de la réponse Leo Sauers échoue si le caractère se trouve au début de la chaîne . 

var needle ='A',
  haystack = 'AbcAbcAbc';

haystack.split('').map( function(e,i){ if(e === needle) return i;} )
  .filter(Boolean).length;

donnera 2 au lieu de 3, car la fonction de filtrage Boolean donne false pour 0.

Autre fonction de filtrage possible:

haystack.split('').map(function (e, i) {
  if (e === needle) return i;
}).filter(function (item) {
  return !isNaN(item);
}).length;
0
saltimbokka

Voici ma solution. Beaucoup de solutions déjà postées devant moi. Mais j'aime partager mon point de vue ici.

const mainStr = 'str1,str2,str3,str4';

const commaAndStringCounter = (str) => {
  const commas = [...str].filter(letter => letter === ',').length;
  const numOfStr = str.split(',').length;

  return `Commas: ${commas}, String: ${numOfStr}`;
}

// Run the code
console.log(commaAndStringCounter(mainStr)); // Output: Commas: 3, String: 4

Ici vous trouvez mon REPL

0
Jamal Uddin

Ma solution avec ramda js:

const testString = 'somestringtotest'

const countLetters = R.compose(
  R.map(R.length),
  R.groupBy(R.identity),
  R.split('')
)

countLetters(testString)

Lien vers REPL.

0
Michal

Je pense que vous trouverez la solution ci-dessous très courte, très rapide, capable de travailler avec de très longues chaînes, capable de supporter plusieurs recherches de caractères, de vérifier les erreurs et de gérer des recherches de chaînes vides.

function substring_count(source_str, search_str, index) {
    source_str += "", search_str += "";
    var count = -1, index_inc = Math.max(search_str.length, 1);
    index = (+index || 0) - index_inc;
    do {
        ++count;
        index = source_str.indexOf(search_str, index + index_inc);
    } while (~index);
    return count;
}

Exemple d'utilisation:

console.log(substring_count("Lorem ipsum dolar un sit amet.", "m "))

function substring_count(source_str, search_str, index) {
    source_str += "", search_str += "";
    var count = -1, index_inc = Math.max(search_str.length, 1);
    index = (+index || 0) - index_inc;
    do {
        ++count;
        index = source_str.indexOf(search_str, index + index_inc);
    } while (~index);
    return count;
}

Le code ci-dessus corrige le principal bogue de performance de Jakub Wawszczyk, selon lequel le code cherche toujours une correspondance, même après que indexOf a déclaré qu'il n'en existait aucune et que sa version elle-même ne fonctionnait pas, car il avait oublié de donner les paramètres d'entrée de la fonction.

0
Jack Giffin

La méthode la plus rapide semble être via l'opérateur d'index:

function charOccurances (str, char)
{
    for (var c = 0, i = 0, len = str.length; i < len; ++i)
    {
        if (str[i] == char)
        {
            ++c;
        }
    }
    return c;
}

Usage:

charOccurances('example/path/script.js', '/') == 2

Ou en tant que fonction prototype:

String.prototype.charOccurances = function (char)
{
    for (var c = 0, i = 0, len = this.length; i < len; ++i)
    {
        if (this[i] == char)
        {
            ++c;
        }
    }
    return c;
}

Usage:

charOccurances('example/path/script.js', '/') == 2
0
zoran404