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.

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.


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


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

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

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


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.


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.


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


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.


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


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


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

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


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

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


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


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.");
}

1
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++

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;


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


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

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

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!


0

Solusi saya:

function countOcurrences(str, value){
   var regExp = new RegExp(value, "gi");
   return str.match(regExp) ? str.match(regExp).length : 0;  
}

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;

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

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.


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.


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.


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;

} 

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.