Hitung jumlah kemunculan karakter dalam string dalam Javascript

525

Saya perlu menghitung jumlah kemunculan karakter dalam sebuah string.

Misalnya, string saya berisi:

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

Saya ingin mencari jumlah ,karakter koma , yaitu 3. Dan jumlah string individu setelah dibagi bersama koma, yaitu 4.

Saya juga perlu memvalidasi bahwa masing-masing string yaitu str1 atau str2 atau str3 atau str4 tidak boleh melebihi, katakanlah, 15 karakter.

Cur
sumber

Jawaban:

766

Saya telah memperbarui jawaban ini. Saya menyukai gagasan menggunakan korek api lebih baik, tetapi lebih lambat:

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

Gunakan literal ekspresi reguler jika Anda tahu apa yang Anda cari sebelumnya, jika tidak, Anda bisa menggunakan RegExpkonstruktor, dan meneruskan gbenderanya sebagai argumen.

matchkembali nulltanpa hasil demikian|| []

Jawaban asli yang saya buat pada tahun 2009 di bawah ini. Ini menciptakan sebuah array yang tidak perlu, tetapi menggunakan pemisahan lebih cepat (pada September 2014). Saya ambivalen, jika saya benar-benar membutuhkan kecepatan tidak akan ada pertanyaan bahwa saya akan menggunakan split, tapi saya lebih suka menggunakan pertandingan.

Jawaban lama (mulai 2009):

Jika Anda mencari koma:

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

Jika Anda mencari str

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

Baik dalam jawaban @Llo dan dalam uji jsperf konyol saya sendiri muncul dengan cepat, setidaknya di Chrome, tetapi sekali lagi membuat array tambahan sepertinya tidak waras.

Bjorn
sumber
8
tes menunjukkan Firefox jauh lebih cepat daripada browser lain saat membelah. jsperf.com/count-the-number-of-occurances-in-string
vsync
4
Eh, saya baru saja menguji vsync's jsperf dan regex lebih lambat di Chrome, Firefox dan IE. 68%, 100%, dan 14% masing-masing. Saya punya i7 2600.
Moss
57
Saya benar-benar tidak menyukai gagasan menggunakan regex karena "Anda menyukainya lebih baik". Regex memiliki tujuan, tetapi umumnya ketika ada solusi non-regex sederhana itu adalah pilihan yang lebih baik. Perhatikan juga bahwa kedua metode membuat array, jadi itu juga bukan alasan untuk menggunakan regex.
Jasper
4
Saya lebih suka dalam hal ini karena suatu alasan. Memisahkan sebuah string menjadi sebuah array untuk mendapatkan sejumlah kemunculan adalah cara bulat untuk mendapatkan informasi itu. Memisahkan array hanya lebih cepat karena detail implementasi, sesuatu yang dapat berubah, sedangkan mendapatkan jumlah kecocokan adalah peningkatan keterbacaan, maksudnya jelas dan tidak membuat dan mengisi struktur data yang tidak digunakan.
Bjorn
30
split () adalah alat dasar dalam javascript, secara konsep sederhana, dan menghitung pemisahan memberikan maksud yang jelas dan benar-benar dapat dibaca.
bradw2k
217

Setidaknya ada empat cara. Pilihan terbaik, yang seharusnya menjadi yang tercepat untuk mesin RegEx asli -, ditempatkan di bagian atas. jsperf.com saat ini sedang down, kalau tidak saya akan memberikan Anda statistik kinerja.

Pembaruan : Tolong, cari tes kinerja di sini , dan jalankan sendiri, sehingga dapat berkontribusi hasil kinerja Anda. Spesifikasi hasil akan diberikan nanti.

1.

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

2.

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

perpecahan tidak direkomendasikan. Sumberdaya lapar. Alokasikan instance 'Array' baru untuk setiap pertandingan. Jangan coba itu untuk file> 100MB melalui FileReader. Anda sebenarnya dapat dengan mudah mengamati penggunaan sumber daya EXACT menggunakan opsi profiler 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.

mencari satu karakter

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

Memperbarui:

5.

pemetaan elemen dan penyaringan, tidak direkomendasikan karena preallokasi sumber daya keseluruhan daripada menggunakan 'generator' 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

Bagikan: Saya membuat intisari ini , dengan 8 metode penghitungan karakter saat ini, sehingga kami dapat langsung menyatukan dan berbagi ide-ide kami - hanya untuk bersenang-senang, dan mungkin beberapa tolok ukur yang menarik :)

https://gist.github.com/2757250

Lorenz Lo Sauer
sumber
27
Butuh beberapa saat untuk menyadari apa yang ||[]sedang dilakukan tetapi jawaban ini luar biasa! Untuk orang lain yang menggaruk-garuk kepala mereka, match()kembali nulljika tidak ada kecocokan yang ditemukan dan ||[]akan mengembalikan array 0 panjang jika match()kembali null, artinya length()akan mengembalikan 0 bukannya menghasilkan kesalahan jenis.
Nathan
1
Nathan, untuk pembelaan saya, saya menguraikan hal itu sebelum menulis kode di atas: gist.github.com/2757164 . Saya ingin menghindari posting blog dari potongan kode kecil, yang bagaimanapun akan memungkinkan Anda akses instan melalui pencarian google. Intisari sebagai repositori cuplikan sangat jarang diindeks dan kurang ideal. PS: Saya juga benci keanehan sintaksis yang tidak jelas.
Lorenz Lo Sauer
2
Lo Sauer, tidak perlu membela diri, kodenya solid dan saya belajar sesuatu sendiri dengan mencari tahu cara kerjanya :) Saya lebih suka metode ini daripada apa yang sebenarnya ditandai sebagai jawabannya. Seharusnya tidak perlu membagi string jika kita tidak akan menggunakan hasilnya.
Nathan
3
Metode ketiga Anda (juga, sayangnya, tercepat), akan melewatkan pertandingan di indeks 0 di tumpukan jerami. Anda dapat memperbaikinya dengan menggunakan do ... while, sebagai gantinya: var strsearch = "o", str = "ini adalah foo bar", index = -1, count = -1; do {index = str.indexOf (strsearch, index + 1); hitung ++; } while (index! = -1); hitung
Augustus
1
Cukup untuk memulai index = -2, tapi terima kasih banyak @Austustus
Lorenz Lo Sauer
18

Tambahkan fungsi ini ke prototipe sengatan:

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

pemakaian:

console.log("strings".count("s")); //2
Philippe Boissonneault
sumber
bagaimana "stringsstringstrings".count("str")?
Toskan
12

Pencarian Google cepat mendapatkan ini (dari 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;
}

Gunakan seperti ini:

test = 'one,two,three,four'
commas = test.count(',') // returns 3
pengguna253751
sumber
4
error on *char ( SyntaxError: nothing to repeat)
1
argumennya harus berupa ungkapan reguler. Jadi, jika Anda ingin menghitung , Anda harus mengirim '[* ]'
Gerard ONeill
8

Cukup, gunakan pemisahan untuk mencari tahu jumlah kemunculan karakter dalam sebuah string.

mainStr.split(',').length // memberikan 4 yang merupakan jumlah string setelah pemisahan menggunakan pembatas koma

mainStr.split(',').length - 1 // memberikan 3 yang merupakan jumlah koma

Pranjal Successena
sumber
Ini pada dasarnya jawaban yang diperlukan di sini. Saya terkejut belum ada yang menunjukkan.
Rohit Gupta
7

Berikut adalah solusi yang serupa, tetapi menggunakan Array.prototype.reduce

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

Seperti yang disebutkan, String.prototype.splitbekerja jauh lebih cepat daripada String.prototype.replace.

uladzimir
sumber
6

Saya telah menemukan bahwa pendekatan terbaik untuk mencari karakter dalam string yang sangat besar (misalnya, panjangnya 1.000 000 karakter) adalah dengan menggunakan replace()metode ini.

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

Anda dapat melihat suite JSPerf lain untuk menguji metode ini bersama dengan metode lain untuk menemukan karakter dalam sebuah string.

Valera Rozuvan
sumber
Jelas bahwa jika kode Anda entah bagaimana berulang lebih dari satu juta karakter 500.000 kali per detik, CPU saya berjalan setidaknya 100GHz (dengan asumsi tidak ada SIMD; bahkan kemudian akan setidaknya 40GHz). Jadi saya tidak percaya bahwa tolok ukur ini benar.
kata ganti saya adalah monicareinstate
5

Anda juga dapat mengistirahatkan string dan bekerja dengannya seperti array elemen yang digunakan

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

console.log(commas);

Atau

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

console.log(commas);

Yosvel Quintero Arguelles
sumber
1
Yang kedua berguna, terima kasih!
AlexGera
4

Saya membuat sedikit perbaikan pada jawaban yang diterima, memungkinkan untuk memeriksa dengan pencocokan case-sensitive / case-sensitive, dan merupakan metode yang dilampirkan pada objek string:

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

lit adalah string untuk mencari (seperti 'ex'), dan cis adalah case-insensitivity, default ke false, itu akan memungkinkan untuk pemilihan yang tidak sensitif case.


Untuk mencari string 'I love StackOverflow.com'huruf kecil 'o', Anda akan menggunakan:

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

amount_of_osakan sama dengan 2.


Jika kami harus mencari string yang sama lagi menggunakan pencocokan case-sensitive, Anda akan menggunakan:

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

Kali ini, amount_of_osakan sama dengan 3, karena modal Odari string akan dimasukkan dalam pencarian.

Dendromaniac
sumber
4

ok, yang lain dengan regexp - mungkin tidak cepat, tetapi lebih pendek dan lebih mudah dibaca daripada yang lain, dalam kasus saya hanya '_'untuk menghitung

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

hapus saja semua yang tidak terlihat seperti char Anda tetapi tidak terlihat bagus dengan string sebagai input

setengah bit
sumber
4

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

Clive Paterson
sumber
4

Cara termudah yang saya temukan ...

Contoh-

str = 'mississippi';

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

find_occurences(str, 'i') //outputs 4
Ankur Choraywal
sumber
ringkas! Terima kasih!
LeOn - Han Li
3

Saya sedang mengerjakan proyek kecil yang membutuhkan penghitung sub-string. Mencari frasa yang salah tidak memberi saya hasil, namun setelah menulis implementasi saya sendiri saya telah menemukan pertanyaan ini. Ngomong-ngomong, ini cara saya, mungkin lebih lambat dari kebanyakan di sini, tetapi mungkin bermanfaat bagi seseorang:

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/

Tolong beri tahu saya jika Anda menemukan implementasi ini gagal atau tidak mengikuti beberapa standar! :)

PEMBARUAN Anda mungkin ingin mengganti:

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

Dengan:

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

Baca menarik membahas hal di atas: http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value

Jakub Wawszczyk
sumber
1
Ya, dan itu akan berhasil untuk substring, bukan hanya subchars. Namun, Anda perlu menambahkan parameter ke fungsi :)
Nico
2

Jika Anda menggunakan lodash, metode _.countBy akan melakukan ini:

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

Metode ini juga berfungsi dengan array:

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

Ini solusinya. Banyak solusi yang sudah diposting sebelum saya. Tapi saya suka berbagi pandangan saya di sini.

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

Di sini Anda menemukan REPL saya

Md. Jamal Uddin
sumber
2

Metode tercepat tampaknya melalui operator indeks:

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

console.log( charOccurances('example/path/script.js', '/') ); // 2

Atau sebagai fungsi prototipe:

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

console.log( 'example/path/script.js'.charOccurances('/') ); // 2

zoran404
sumber
1

Berikut ini menggunakan ekspresi reguler untuk menguji panjangnya. testex memastikan Anda tidak memiliki 16 atau lebih karakter non-koma berturut-turut. Jika lulus tes, maka hasil untuk membagi string. menghitung koma semudah menghitung token dikurangi satu.

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.");
}
Jonathan Fingland
sumber
1
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++
wlf
sumber
1

Bagaimana dengan string.split (diinginkanCharecter) .length-1

Contoh:

var str = "hellow how is life"; var len = str.split ("h"). length-1; akan memberikan hitungan 2 untuk karakter "h" dalam string di atas;

pengguna2296195
sumber
1

Saya menggunakan Node.js v.6.0.0 dan yang tercepat adalah yang dengan indeks (metode ke-3 dalam jawaban Lo Sauer).

Yang kedua adalah:

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

Marc K.
sumber
1

Inilah salah satu yang hampir secepat metode split dan replace, yang sedikit lebih cepat daripada metode regex (dalam chrome).

var num = 0;
for (ch of "str1,str2,str3,str4")
{
    if (ch === ',') num++;
}
Gerard ONeill
sumber
1

Saya baru saja melakukan tes yang sangat cepat dan kotor pada repl.it menggunakan Node v7.4. Untuk satu karakter, standar untuk loop paling cepat:

Beberapa kode :

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

Hasil dari beberapa proses :

 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
NuSkooler
sumber
1

Dan ada:

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

Bekerja dengan bilangan bulat juga!

Damion Dooley
sumber
0

Solusi saya:

function countOcurrences(str, value){
   var regExp = new RegExp(value, "gi");
   return str.match(regExp) ? str.match(regExp).length : 0;  
}
Gere
sumber
Ini tidak akan berfungsi sebagai String.prototype.matchpengembalian nulltanpa kecocokan. Itu berarti tidak ada referensi ke objek dengan lengthatribut. Dengan kata lain:String.prototype.match.call('willnotwork', /yesitwill/) === null
Lorenz Lo Sauer
0

Metode kelima dalam jawaban Leo Sauers gagal, jika karakternya ada di awal string. misalnya

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

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

akan memberikan 2 sebagai ganti 3, karena filter funtion Boolean memberikan false untuk 0.

Fungsi filter lain yang mungkin:

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

Saya tahu ini mungkin pertanyaan lama tapi saya punya solusi sederhana untuk pemula tingkat rendah dalam JavaScript.

Sebagai seorang pemula, saya hanya bisa memahami beberapa solusi untuk pertanyaan ini, jadi saya menggunakan dua loop FOR bersarang untuk memeriksa setiap karakter terhadap setiap karakter lain dalam string, menambah variabel jumlah untuk setiap karakter yang ditemukan yang sama dengan karakter itu.

Saya membuat objek kosong baru di mana setiap kunci properti adalah karakter dan nilainya berapa kali setiap karakter muncul dalam string (hitung).

Fungsi contoh: -

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;
}
Viscount Wathika
sumber
0

Saya percaya Anda akan menemukan solusi di bawah ini menjadi sangat singkat, sangat cepat, dapat bekerja dengan string yang sangat panjang, mampu mendukung beberapa pencarian karakter, bukti kesalahan, dan mampu menangani pencarian string kosong.

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

Contoh penggunaan:

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

Kode di atas memperbaiki bug kinerja utama di Jakub Wawszczyk bahwa kode terus mencari kecocokan bahkan setelah indexOf mengatakan tidak ada dan versinya sendiri tidak berfungsi karena dia lupa memberikan parameter input fungsi.

Jack Giffin
sumber
0
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);

Dalam javascript Anda dapat menggunakan kode di atas untuk mendapatkan kemunculan karakter dalam sebuah string.

Nitin.
sumber
0

Solusi saya dengan ramda js:

const testString = 'somestringtotest'

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

countLetters(testString)

Tautan ke REPL.

Michal
sumber
0

Fungsi mengambil string str sebagai parameter dan menghitung kemunculan setiap karakter unik dalam string. Hasilnya datang dalam pasangan kunci - nilai untuk setiap karakter.

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;

} 
Pratibha Singh
sumber
Anda lupa bagian kedua dari pertanyaan: "Saya juga perlu memvalidasi bahwa masing-masing string yaitu str1 atau str2 atau str3 atau str4 tidak boleh melebihi, katakanlah, 15 karakter."
Maxime Launois