Bagaimana cara menghitung kemunculan string dalam string?


609

Bagaimana saya bisa menghitung berapa kali string tertentu terjadi di string lain. Sebagai contoh, inilah yang saya coba lakukan dalam Javascript:

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

19
Itu tergantung pada apakah Anda menerima contoh yang tumpang tindih , misalnya var t = "sss"; Berapa banyak contoh dari "ss" substring dalam string di atas? 1 atau 2? Apakah Anda melompati setiap contoh, atau memindahkan karakter-demi-karakter penunjuk, mencari substring?
Tim

4
Tolok ukur yang ditingkatkan untuk jawaban pertanyaan ini: jsperf.com/string-ocurrence-split-vs-match/2 (berdasarkan tolok ukur Kazzkiq).
idmean

Jawaban:


1030

The gdalam ekspresi reguler (kependekan dari global ) mengatakan untuk mencari seluruh string daripada hanya menemukan kemunculan pertama. Ini cocok isdua kali:

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

Dan, jika tidak ada yang cocok, ia kembali 0:

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


3
modern dan elegan, tetapi solusi Vitimtk jauh lebih efisien. apa yang kalian pikirkan tentang kodenya?
TruMan1

5
Ini menjawab pertanyaan terbaik. Jika seseorang bertanya "Bagaimana saya bisa melakukan ini 10x lebih cepat dalam kasus khusus (tanpa regexps)" Vitimtk akan memenangkan pertanyaan itu.
Dzhaughn

121
Terima kasih untuk ini .. Saya pergi dengan count = (str.match(/is/g) || []).lengthuntuk menangani jika Anda tidak memiliki kecocokan.
Mat

6
Saya tidak berpikir jawaban ini cocok dengan pertanyaan, karena tidak mengambil string sebagai argumen untuk mencocokkan, seperti yang dijelaskan oleh use case. Tentu, Anda dapat membuat secara dinamis regexp menggunakan RegExpkonstruktor dan meneruskan string yang Anda cari, tetapi dalam hal ini Anda harus melarikan diri dari semua metakarakter. Dalam skenario itu, pendekatan string murni lebih disukai.
ZER0

3
Jawaban Matt harus ada dalam jawaban!
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;
}

Pemakaian

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

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

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

allowOverlapping

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

Cocok:

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

Tes Unit

Tolok ukur

Saya telah membuat tes benchmark dan fungsi saya lebih dari 10 kali lebih cepat daripada fungsi pencocokan regexp yang diposting oleh gumbo. Dalam string pengujian saya adalah panjang 25 karakter. dengan 2 kemunculan karakter 'o'. Saya dieksekusi 1.000.000 kali di Safari.

Safari 5.1

Benchmark> Total waktu eksekusi: 5617 ms (regexp)

Benchmark> Total waktu eksekusi: 881 ms (fungsi saya 6.4x lebih cepat)

Firefox 4

Benchmark> Total waktu eksekusi: 8547 ms (Rexexp)

Benchmark> Total waktu eksekusi: 634 ms (fungsi saya 13,5x lebih cepat)


Edit: perubahan yang saya buat

  • panjang substring yang di-cache

  • menambahkan tipe-casting ke string.

  • menambahkan parameter 'allowOverlapping' opsional

  • memperbaiki keluaran yang benar untuk kasus substring kosong.

Inti

5
Saya mengulangi tes ini di Safari 5 dan mendapatkan hasil yang serupa dengan string kecil (100b), tetapi dengan string yang lebih besar (16kb), regex berjalan lebih cepat untuk saya. Untuk satu iterasi (bukan 1.000.000), perbedaannya kurang dari satu milidetik, jadi suara saya masuk ke regex.
arlomedia

2
+1, tetapi Anda memeriksa substring.lengthdi hampir setiap loop, Anda harus mempertimbangkan untuk menyimpannya di luarwhile
ajax333221

1
@ ajax333221 OMG Anda membaca pikiran saya, saya melakukan perbaikan ini beberapa hari yang lalu, dan saya akan mengedit jawaban saya jsperf.com/count-string-occurrence-in-string
Vitim.us

4
Saya menemukan kode Anda digunakan di sini: success-equation.com/mind_reader.html . Sungguh bagus programmer berpikiran menaruh referensi di sana.
Bruno Kim

3
@DanielZuzevich itu akan memaksa tipe ke String , jika Anda melakukannya occurrences(11,1) //2dan masih akan bekerja. (Lebih cepat melakukan cara ini daripada memeriksa jenis dan memanggil toString () )
Vitim.us

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

4
Ini adalah tidak aman / pendekatan yang tidak akurat, misalnya: countInstances("isisisisisis", "is") === 0.
Nick Craver

5
@Antal - Sepertinya bug pada beta build sebelumnya dari chrome, berfungsi setelah memperbarui ke yang terbaru, saya masih menghindari metode ini.
Nick Craver

28
Ini terlihat seperti solusi yang sangat valid bagi saya.
Gregor Schmidt

2
@NickCraver karena penasaran, mengapa Anda ingin menghindari metode ini? (selain bug di browser beta Anda)
Jonny Lin

6
@ JonnyLin itu membuat alokasi yang tidak perlu Anda segera membuang ketika alternatif tidak - yang berpotensi sangat besar tergantung pada data.
Nick Craver

88

Anda dapat mencoba ini:

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


14
+1 untuk kesederhanaan dan karena menurut pengujian saya solusi ini berjalan ~ 10x lebih cepat dari yang lain!
Claudio Holanda

Misalnya saya punya dua "adalah" bagaimana Anda mendapatkan posisi masing-masing?
rapidoodle

Sebagaimana dibahas dalam jawaban @Orbit, orang mendapatkan hasil berbeda pada versi Chrome yang lebih lama. Saya mungkin akan sedikit berhati-hati menggunakan metode ini.
mgthomas99

Dan Anda juga dapat menggunakannya dengan variabel: theString.split(myvar).length - 1yang Anda tidak bisa dengan regex sederhana
Steffan

4
Inilah jawaban @Orbit tiga tahun kemudian ...
aloisdg pindah ke codidact.com

33

Solusi saya:

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
mungkin akan lebih baik untuk mengembalikan (str.match (regExp) || []). length; Dengan begitu Anda tidak mengevaluasi ekspresi reguler dua kali?
aikeru

2
Anda juga perlu menilai string Anda atau countOcurrences('Hello...','.')==8bukan 3
Vitim.us

19

Anda dapat menggunakan matchuntuk mendefinisikan fungsi tersebut:

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

1
Jika Anda ingin agar seragam dengan semantik pencarian JS, garis balik akan menjadi return m ? m.length:-1;.
Conor O'Brien

Ini lebih baik daripada solusi regex lainnya di atas, karena mereka menyebabkan kesalahan jika string untuk menghitung kemunculan adalah "[" atau apa pun dengan makna khusus di Regex.
programmer5000

11

Versi 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. Ini hanya untuk pencarian char tunggal, terlalu halus 2. bahkan OP meminta iskejadian
vladkras

1
Ini mungkin implementasi tercepat di sini, tetapi akan lebih cepat jika Anda mengganti "++ pos" dengan "pos + = searchFor.length"
hanshenrik



8

Inilah fungsi tercepat!

Kenapa lebih cepat?

  • Tidak memeriksa char by char (dengan 1 pengecualian)
  • Menggunakan beberapa saat dan menambah 1 var (char count var) vs. a untuk loop memeriksa panjang dan menambah 2 var (biasanya var i dan var dengan jumlah char)
  • Menggunakan WAY less vars
  • Tidak menggunakan regex!
  • Menggunakan fungsi (semoga) yang sangat optimal
  • Semua operasi digabungkan sebagaimana mestinya, menghindari perlambatan karena beberapa operasi

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

Ini versi yang lebih lambat dan lebih mudah dibaca:

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

Yang ini lebih lambat karena meja, nama var panjang dan penyalahgunaan 1 var.

Untuk menggunakannya, Anda cukup melakukan ini:

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

Edit: (2013/12/16)

JANGAN gunakan dengan Opera 12.16 atau lebih lama! itu akan memakan waktu hampir 2,5x lebih banyak daripada solusi regex!

Pada Chrome, solusi ini akan membutuhkan antara 14ms dan 20ms untuk 1.000.000 karakter.

Solusi regex membutuhkan 11-14ms untuk jumlah yang sama.

Menggunakan fungsi (di luar String.prototype) akan memakan waktu sekitar 10-13ms.

Berikut adalah kode yang digunakan:

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

Hasil dari semua solusi harus 100.000!

Catatan: Jika Anda ingin fungsi ini untuk menghitung lebih dari 1 char, perubahan mana c=(c+'')[0]dalamc=c+''


1
prototipe itu SEBUAH CONTOH! Anda dapat menggunakan fungsi sesuka Anda! Anda bahkan dapat melakukan ini: var timesFunctionExist = fungsi (x, c) {var t = 0, l = 0, c = (c + '') [0]; sementara (l = x.indexOf (c, l) +1 ) ++ t; return t}); alert (timesCharExist ('Char "a" hanya muncul dua kali', 'a')) ;! (Ini akan mempercepat sedikit lebih banyak karena saya tidak akan main-main dengan prototipe). Jika Anda pikir saya salah, mengapa Anda tidak menunjukkannya sebelum melempari saya dengan batu? Buktikan kepada saya bahwa fungsi saya menyebalkan dan saya akan menerimanya. Tunjukkan pada saya test case. Dan panjang vars memang memengaruhi kecepatan. Anda bisa mengujinya.
Ismael Miguel

7

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


4

Saya pikir tujuan untuk regex jauh berbeda indexOf. indexOfcukup temukan kemunculan string tertentu sementara di regex Anda dapat menggunakan wildcard seperti [A-Z]yang artinya akan menemukan karakter kapital apa pun dalam kata tersebut tanpa menyatakan karakter yang sebenarnya.

Contoh:

 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 tua, tapi saya perlu melakukan sesuatu seperti ini hari ini dan hanya berpikir untuk memeriksa SO sesudahnya. Bekerja sangat cepat untukku.

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

Refer: - hitung substring yang muncul di string untuk penjelasan langkah demi langkah.


3

Membangun berdasarkan Vittim.us jawaban di atas. Saya suka kontrol yang diberikan metodenya, membuatnya mudah diperluas, tetapi saya perlu menambahkan ketidaksensitifan huruf besar dan membatasi kecocokan pada seluruh kata dengan dukungan tanda baca. (mis. "mandi" dalam "mandi." tetapi tidak "mandi")

Regex tanda baca berasal dari: https://stackoverflow.com/a/25575009/497745 ( Bagaimana cara menghapus semua tanda baca dari sebuah string dalam JavaScript menggunakan 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;
}

Jangan ragu untuk memodifikasi dan memperbaiki jawaban ini jika Anda menemukan bug atau peningkatan.


3

Bagi siapa pun yang menemukan utas ini di masa mendatang, perhatikan bahwa jawaban yang diterima tidak akan selalu mengembalikan nilai yang benar jika Anda menggeneralisasi, karena itu akan mencekik operator regex seperti $dan .. Ini versi yang lebih baik, yang dapat menangani jarum apa pun :

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

Gunakan get_occurrence (varS, string) untuk menemukan kemunculan kedua karakter dan string dalam sebuah String.


2

Cobalah

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

Tidak ada yang akan melihat ini, tapi ada baiknya untuk mengembalikan fungsi rekursi dan panah sesekali (pun dengan maksud yang mulia)

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


1

Sekarang ini adalah utas yang sangat lama saya temui tetapi karena banyak yang mendorong jawaban mereka, inilah milik saya dengan harapan dapat membantu seseorang dengan kode sederhana ini.

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

Saya tidak yakin apakah itu solusi tercepat tetapi saya lebih suka untuk kesederhanaan dan untuk tidak menggunakan regex (saya hanya tidak suka menggunakannya!)


1

Fungsi ini mengembalikan jumlah kemunculan kata dalam teks.

Catatan kami menggunakan toLowerCase untuk menghitung jumlah kemunculan apa pun format (huruf besar, huruf besar ...) dari kata dan teks

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

0

Jawaban untuk Leandro Batista: hanya masalah dengan ekspresi 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

Agak terlambat tetapi, dengan asumsi kita memiliki string berikut:

var temp = "This is a string.";

Pertama kami membagi pada apa pun yang Anda ingin mencocokkan, ini akan mengembalikan serangkaian string.

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

Kemudian kita mendapatkan panjangnya dan mengurangi 1 ke sana karena membagi default ke array ukuran 1 dan akibatnya menambah ukurannya setiap kali ia menemukan kejadian.

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

Anda juga dapat melakukan semua ini dalam satu baris sebagai berikut:

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

Semoga bisa membantu: D


1
Bisakah saya menandai ini sebagai jawaban rangkap? Mungkin Anda harus membaca semua jawaban sebelum memberikan jawaban Anda sendiri?
Michiel

2
Ini jawaban @Orbit delapan tahun kemudian ...
aloisdg pindah ke codidact.com

1
Haruskah saya menghapus respons ini?
Juan Enrique Segebre

0

Solusi ini didasarkan pada .replace()metode yang menerima RegEx sebagai parameter pertama dan fungsi sebagai parameter kedua yang dapat kita gunakan sebagai penutup untuk menambah penghitung ...

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

Pemakaian

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

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

0

menemukan posting ini.

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
}

Algoritma yang sama dapat ditata lebih pendek:

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 diterjemahkan ke Javascript dari 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
}

Periksa fungsi terjemahan Substr_count dari Locutus tentang Php


-2

Coba ini:

function countString(str, search){
    var count=0;
    var index=str.indexOf(search);
    while(index!=-1){
        count++;
        index=str.indexOf(search,index+1);
    }
    return count;
}
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.