文字列内の文字列の出現を数える方法は?


609

特定の文字列が別の文字列に出現する回数をどのようにカウントできますか?たとえば、これは私がJavascriptでやろうとしていることです:

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

19
重複するインスタンスを受け入れるかどうかによって異なります。例:var t = "sss"; 上記の文字列には、サブストリング「ss」のインスタンスがいくつありますか?1か2?各インスタンスを飛び越えたり、ポインターを文字ごとに移動して部分文字列を探したりしますか?
Tim

4
この質問の回答の改善されたベンチマーク:jsperf.com/string-ocurrence-split-vs-match/2(Kazzkiqのベンチマークに基づく)。
idmean

回答:


1030

g(のために短い正規表現で世界的には)ちょうど最初の発生を見つけるのではなく、文字列全体を検索するために指定します。これはis2回一致します。

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

そして、一致するものがなければ、次を返します0

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


3
モダンでエレガントですが、Vitimtkのソリューションははるかに効率的です。彼のコードをどう思いますか?
TruMan1

5
これは質問に最もよく答えます。誰かが「特別な場合(正規表現なしで)これを10倍速くするにはどうしたらいいですか?」
Dzhaughn、2012年

121
これをありがとう.. count = (str.match(/is/g) || []).lengthあなたが一致していない場合、私は処理に行きました。
Matt

6
ユースケースで説明されているように、この回答は質問に適切に一致するとは思いません。一致する引数として文字列をとらないためです。確かに、RegExpコンストラクターを使用して正規表現を動的に作成し、探している文字列を渡すことができますが、その場合はすべてのメタ文字をエスケープする必要があります。そのシナリオでは、純粋な文字列アプローチが推奨されます。
ZER0

3
マットの答えは答えにあるべきです!
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;
}

使用法

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

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

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

allowOverlapping

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

一致:

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

単体テスト

基準

私はベンチマークテストを行いました。私の関数は、gumboが投稿した正規表現一致関数よりも10倍以上高速です。私のテストでは、文字列の長さは25文字です。文字「o」が2回出現します。サファリで1 000 000回実行しました。

Safari 5.1

ベンチマーク>合計実行時間:5617ミリ秒(正規表現)

ベンチマーク>合計実行時間:881 ms(私の機能は6.4倍高速)

Firefox 4

ベンチマーク>合計実行時間:8547 ms(Rexexp)

ベンチマーク>合計実行時間:634 ms(私の機能は13.5倍高速)


編集:私が行った変更

  • キャッシュされた部分文字列の長さ

  • 文字列に型キャストを追加しました。

  • オプションの「allowOverlapping」パラメーターを追加

  • ""空の部分文字列の大文字小文字の正しい出力を修正しました。

要旨

5
私はSafari 5でこのテストを繰り返し、小さい(100b)文字列でも同様の結果を得ましたが、大きい文字列(16kb)を使用すると、正規表現の実行が速くなりました。1回の反復(1,000,000ではない)の場合、違いはいずれにしてもミリ秒未満だったので、私の投票は正規表現に行きます。
arlomedia 2012

2
+1ですがsubstring.length、ほぼすべてのループをチェックしているので、それを外部でキャッシュすることを検討する必要がありますwhile
ajax333221

1
@ ajax333221 OMGあなたは私の心を読みました、私は数日前にこの改善を行いました、そして私は私の答えを編集しましたjsperf.com/count-string-occurrence-in-string
Vitim.us

4
ここで使用中のコードを見つけました:success-equation.com/mind_reader.html。プログラマーがそこにリファレンスを置くことを本当に気にかけていた。
ブルーノキム

3
@DanielZuzevich型をStringに強制変換します。そうした場合occurrences(11,1) //2でも機能します。(型をチェックしてtoString()を呼び出すよりも、この方法の方が高速です)
Vitim.us

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

4
これは安全ではなく、不正確なアプローチですcountInstances("isisisisisis", "is") === 0。例:
Nick Craver

5
@Antal-Chromeの以前のベータビルドのバグのように見え、最新に更新した後に機能しますが、この方法はまだ避けています。
Nick Craver

28
これは私にとって完全に有効な解決策のように見えます。
グレゴールシュミット

2
好奇心から@NickCraver、なぜこのメソッドを避けたいのですか?(ベータブラウザーのバグ以外)
Jonny Lin

6
@JonnyLinは、代替案が作成しないときにすぐに捨てる不要な割り当てを作成します。データによっては非常に大きな割り当てになる可能性があります。
Nick Craver

88

あなたはこれを試すことができます:

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


14
単純化のために+1、そして私のテストに応じて、このソリューションは他のソリューションよりも最大10倍速く実行されます!
クラウディオホランダ

たとえば、私は2つの「is」を持っています。どのようにしてそれぞれの位置を取得しますか?
rapidoodle

@Orbitの回答で説明したように、人々は古いバージョンのChromeで異なる結果を得ています。この方法を使用する場合、私は少し慎重になるでしょう。
mgthomas99 16

また、変数と一緒に使用することもできます。theString.split(myvar).length - 1これは単純な正規表現ではできません
Steffan

4
これは3年後の@Orbitの回答です...
aloisdgがcodidact.comに移動します。

33

私の解決策:

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
(str.match(regExp)|| [])。length;を返す方が良いでしょう。そうすれば、正規表現を2回評価しないのですか?
aikeru

2
また、文字列をcountOcurrences('Hello...','.')==8
エスケープ

19

を使用matchして、このような関数を定義できます。

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

1
JSの検索セマンティクスで統一したい場合、戻り行はになりますreturn m ? m.length:-1;
Conor O'Brien

これは、他の正規表現ソリューションよりも優れています。これは、出現回数をカウントする文字列が "["または正規表現で特別な意味を持つものである場合にエラーが発生するためです。
programmer5000

11

非正規表現バージョン:

 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.単一文字検索のみであり、微妙すぎる2. OPでもis出現を要求する
vladkras

1
これはおそらくここで最も速い実装ですが、「++ pos」を「pos + = searchFor.length」に置き換えた場合はさらに速くなります
hanshenrik



8

こちらが最速の機能です!

なぜそれが速いのですか?

  • 1文字ずつチェックしない(1つの例外を除く)
  • whileを使用して1 var(charカウントvar)をインクリメントするか、またはforループで長さをチェックして2 varsをインクリメントします(通常はvar iとcharカウントを持つvar)
  • 使用する変数が少ない
  • 正規表現を使用しません!
  • (うまくいけば)高度に最適化された関数を使用します
  • すべての操作は可能な限り結合され、複数の操作による速度低下を回避します

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

これは、低速で読みやすいバージョンです。

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

これは、カウンター、長い変数名、1つの変数の誤用のために遅くなります。

これを使用するには、次のようにします。

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

編集:(2013/12/16)

Opera 12.16以前では使用しないでください!正規表現ソリューションよりも約2.5倍多くかかります!

Chromeでは、このソリューションは1,000,000文字で14ミリ秒から20ミリ秒かかります。

同じ量の正規表現ソリューションは11-14msかかります。

関数の使用(外部で String.prototype)と、約10〜13ミリ秒かかります。

使用されるコードは次のとおりです。

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

すべてのソリューションの結果は100,000になるはずです。

注:この関数で複数の文字をカウントする場合は、どこをc=(c+'')[0]に変更するかc=c+''


1
プロトタイプは例でした!好きなように使える機能です!これを行うこともできます:var timesFunctionExist = function(x、c){var t = 0、l = 0、c =(c + '')[0]; while(l = x.indexOf(c、l)+1 )++ t; tを返す}); alert(timesCharExist( 'char "a"は2回しか表示されません'、 'a'));! (これにより、プロトタイプをいじる必要がなくなるため、もう少しスピードアップします)。もし私が間違っていると思うなら、私に岩を投げる前にそれを見せてはどうですか?私の機能が悪いことを証明してください。私はそれを受け入れます。テストケースを見せて。変数の長さは速度に影響を与えます。あなたはそれをテストすることができます。
Ismael Miguel


4

正規表現の目的はとはかなり異なると思いますindexOfindexOf正規表現であなたのようなワイルドカードを使用できますが、単純に特定の文字列ののoccuranceを見つける[A-Z]ことがありますを意味しているいずれかを実際の文字を記載せずに単語の資本文字を。

例:

 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

とても古いですが、今日はこのようなことをする必要があり、後でSOをチェックすることだけを考えました。私にとってはかなり速く動作します。

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

ステップバイステップの説明については、文字列に出現する部分文字列のカウントを参照してください。


3

上記の@ Vittim.usの回答に基づいて構築。私は彼のメソッドが提供するコントロールが好きで、拡張が簡単ですが、句読点をサポートして、大文字と小文字を区別せず、単語全体に一致を制限する必要がありました。(例えば、「入浴」は「入浴」にありますが、「入浴」にはありません)

句読点の正規表現の由来:https : //stackoverflow.com/a/25575009/497745regexを使用してJavaScriptの文字列からすべての句読点を削除するにはどうすればよいですか?

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

バグや改善点を見つけたら、この回答を自由に変更してリファクタリングしてください。


3

将来的にこのスレッドを見つけた人のために、あなたはそれを一般あれば、それはのような正規表現の演算子に窒息されますので、受け入れられた答えは常に、正しい値を返さないことに注意してください$.。これはより良いバージョンで、どんな針にも対応できます

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

文字列内の文字と文字列の両方の出現を検索するには、get_occurrence(varS、string)を使用します。


2

それを試してみてください

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

誰もこれを目にすることはありませんが、再帰関数と矢印関数を時々復活させるのは良いことです(見事に意図されたしゃれ)

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


1

今これは私が遭遇した非常に古いスレッドですが、多くの人が答えをプッシュしたので、この簡単なコードで誰かを助けることを期待してここにあります。

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

それが最速の解決策かどうかはわかりませんが、私は単純さと正規表現を使用しないためにそれを好みました(私はそれらを使用したくないだけです!)


1

この関数は、テキスト内の単語の出現回数を返します。

toLowerCaseを使用して、単語とテキストの形式(大文字、大文字など)に関係なく出現回数を計算することに注意してください

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

0

Leandro Batistaへの回答:正規表現の問題です。

 "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

少し遅れますが、次の文字列があるとします。

var temp = "This is a string.";

まず、一致させたいものを分割します。これにより、文字列の配列が返されます。

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

次に、splitはデフォルトでサイズ1の配列になり、その結果、オカレンスが見つかるたびにサイズが増加するため、その長さを取得して1を減算します。

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

次のように、これらすべてを1行で行うこともできます。

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

それが役に立てば幸い:D


1
これに重複回答としてフラグを付けることはできますか?多分あなたはあなた自身のものを提供する前にすべての答えを読むべきですか?
ミシェル

2
これは@Orbitのある答え ... 8年後
codidact.comに移動aloisdg

1
この応答を削除する必要がありますか?
Juan Enrique Segebre

0

この解決策は.replace()、RegExを最初のパラメーターとして受け入れ、関数をクロージャーとして使用してカウンターをインクリメントできるメソッドに基づいています ...

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

使用法

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

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

0

この投稿に出くわしました。

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
}

同じアルゴリズムを短くレイアウトできます:

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 PHPからJavaScriptに翻訳


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
}

LocutusによるPhpのsubstr_count関数の翻訳を確認してください。


-2

これを試して:

function countString(str, search){
    var count=0;
    var index=str.indexOf(search);
    while(index!=-1){
        count++;
        index=str.indexOf(search,index+1);
    }
    return count;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.