JavaScriptの文字列内の文字の出現回数を数えます


525

文字列内の文字の出現回数を数える必要があります。

たとえば、私の文字列に次のものが含まれているとします。

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

カンマ,文字の数、つまり3 を検索します。コンマに沿って分割した後の個々の文字列の数、つまり4 を検索します。

また、各文字列、つまりstr1またはstr2またはstr3またはstr4が、たとえば15文字を超えないことを検証する必要があります。

回答:


766

この回答を更新しました。私はマッチをうまく使うというアイデアが好きですが、遅いです:

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

事前に検索対象がわかっている場合は正規表現リテラルを使用します。RegExpコンストラクタを使用できない場合は、gフラグを引数として渡します。

matchnull結果を返さず、したがって|| []

2009年に私が出した最初の答えは以下のとおりです。不必要にアレイを作成しますが、スプリットを使用すると高速になります(2014年9月現在)。私は両義的です。本当に速度が必要な場合は、スプリットを使用することは間違いありませんが、マッチを使用したいと思います。

以前の回答(2009年から):

コンマを探している場合:

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

strを探している場合

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

@Loの回答でも、私の独自のばかげたjsperfテスト分割でも、少なくともChromeでは速度が進んでいますが、追加の配列を作成することは、正気に思えません。


8
テストでは、Firefoxが分割時に他のどのブラウザーよりもはるかに高速であることを示しています。jsperf.com/count-the-number-of-occurances-in-string
vsync

4
ええと、vsyncのjsperfをテストしたところ、Chrome、Firefox、IEでは正規表現が遅くなりました。それぞれ68%、100%、14%。私はi7の2600持っている
モス

56
「あなたはそれが好き」という理由で、私は正規表現を使用するという考えを本当に嫌っています。正規表現には目的がありますが、一般的に、単純な非正規表現ソリューションがある場合は、それがより適切な選択です。また、どちらの方法でも配列が作成されるため、正規表現を使用する理由にもなりません。
Jasper

4
この場合、私はそれが理由でより好きです。文字列を配列に分割して出現回数を取得することは、その情報を取得するためのラウンドアラウンド方法です。配列の分割は、実装の詳細、変更の可能性があるためにのみ高速ですが、一致数を取得すると読みやすさが向上しますが、意図は明白であり、未使用のデータ構造を作成して埋めることはありません。
ビョルン2014

30
split()は、JavaScriptの基本的なツールであり、概念的には単純です。分割を数えると、意図が明確になり、完全に読みやすくなります。
bradw2k 2015

217

少なくとも4つの方法があります。最高のオプションは、ネイティブのRegExエンジンにより、最速であるはずですが、一番上に配置されます。jsperf.comは現在ダウンしています。それ以外の場合は、パフォーマンス統計を提供します。

更新:パフォーマンステストをここで見つけてください自分で実行して、パフォーマンス結果に貢献してください。結果の詳細は後で説明します。

1。

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

2。

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

分割は推奨されません。リソースが不足しています。一致ごとに「配列」の新しいインスタンスを割り当てます。FileReaderを介して100MBを超えるファイルに対してそれを試さないでください。実際には、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。

単一の文字を検索する

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

更新:

5。

要素のマッピングとフィルタリング。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

共有: 私はこの要旨を作成しました。現在8つの文字カウント方法を使用しているため、アイデアを直接プールして共有できます。

https://gist.github.com/2757250


27
||[]をしているのか理解するのに少し時間がかかりましたが、この答えは素晴らしいです!誰が彼らの頭、傷のためのmatch()リターンをnull一致が見つからない場合は||[]場合は長さ0の配列を返しますmatch()戻りnull意味、length()型エラーを生成する代わりに0のを返します。
Nathan

1
ネイサン、私の弁護のために、上記のコードを書く前に、それについて詳しく説明しました:gist.github.com/2757164。小さなコードのブログ投稿は避けたいのですが、google-searchからすぐにアクセスできました。スニペットリポジトリとしての要点は、インデックスが非常にまばらで、理想的とは言えません。PS:私も不明瞭な構文の特異性を嫌います。
Lorenz Lo Sauer

2
Lo Sauer、自分を守る必要はありません。コードはしっかりしていて、それがどのように機能するかを理解することで自分で何かを学びました:)私は実際に答えとしてマークされているものよりもこの方法を好みます。結果を使用しない場合は、文字列を分割する必要はありません。
Nathan

3
3番目の方法(残念ながら最速です)では、干し草のインデックス0での一致が見落とされます。代わりにdo ... whileループを使用して修正できます。varstrsearch = "o"、str = "othis is foo bar"、index = -1、count = -1; do {index = str.indexOf(strsearch、index + 1); count ++; } while(index!= -1); カウント
Augustus

1
開始を設定するだけで十分ですindex = -2が、@ Augustusに感謝します
Lorenz Lo Sauer

18

この関数をstingプロトタイプに追加します。

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

使用法:

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

どう"stringsstringstrings".count("str")ですか?
トスカン

12

簡単なGoogle検索でこれが得られました(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;
}

次のように使用します。

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

4
*char(SyntaxError: nothing to repeat)のエラー

1
引数は正規表現でなければなりません。したがって、をカウントする場合は、「[* ]」を送信する必要があります
Gerard ONeill

8

単純に、splitを使用して、文字列内の文字の出現回数を調べます。

mainStr.split(',').length //区切りカンマを使用して分割した後の文字列の数である4を与えます

mainStr.split(',').length - 1 //コンマの数である3を与えます


これは基本的にここで必要な答えです。私はまだ誰も指摘していないことにショックを受けています。
Rohit Gupta

7

これは同様のソリューションですが、使用します Array.prototype.reduce

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

すでに述べたように、String.prototype.splitはよりもはるかに高速に動作しString.prototype.replaceます。


6

非常に大きな文字列(たとえば、1 000 000文字)の文字を検索する最善のreplace()方法は、メソッドを使用することです。

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

あなたは見ることができるさらに別のJSPerfのスイートは、文字列内の文字を発見する他の方法と一緒に、このメソッドをテストします。


コードが1秒間に500000回100万文字以上反復する場合、CPUが少なくとも100GHzで動作していることは明らかです(SIMDがないと仮定した場合でも、少なくとも40GHzになります)。したがって、私はこのベンチマークが正しいとは信じていません。
私の代名詞は

5

文字列を休めて、要素の配列のように操作することもできます

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

console.log(commas);

または

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

console.log(commas);


1
2つ目は便利です。ありがとうございます。
AlexGera

4

受け入れられた回答を少し改善しました。これにより、大文字と小文字を区別する/区別しないマッチングでチェックでき、文字列オブジェクトに添付されるメソッドです。

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

lit 検索する文字列です( 'ex'など)。cisは大文字と小文字を区別しません。デフォルトはfalseで、大文字と小文字を区別しない一致を選択できます。


'I love StackOverflow.com'小文字 の文字列を検索するには'o'、次のようにします。

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

amount_of_os に等しいだろう 2


大文字と小文字を区別しないマッチングを使用して同じ文字列を再度検索する場合は、次のようにします。

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

今回は文字列の大文字が検索に含まれるため、にamount_of_os等しくなります。3O


4

わかりました、他の正規表現-おそらく速くはありませんが、私の場合は他の人より短くて読みやすくなっ'_'ています

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

charのように見えないものはすべて削除しますが、文字列を入力として使用すると見栄えがしません


4

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

私が見つけた最も簡単な方法...

例-

str = 'mississippi';

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

find_occurences(str, 'i') //outputs 4

簡潔!ありがとう!
LeOn-Han Li

3

サブストリングカウンターを必要とする小さなプロジェクトに取り組んでいました。間違った語句を検索しても結果は得られませんでしたが、独自の実装を作成した後、この質問に遭遇しました。とにかく、ここは私のやり方です、おそらくここよりも遅いですが、誰かに役立つかもしれません:

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/

この実装が失敗した場合、または一部の標準に従っていない場合は、お知らせください。:)

更新 あなたは代わりにしたいかもしれません:

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

と:

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

上記についての興味深い読み:http : //www.erichynds.com/blog/javascript-length-property-is-a-stored-value


1
はい、それはサブ文字だけでなくサブ文字列でも機能します。ただし、関数にパラメーターを追加する必要があります:)
Nico

2

lodashを使用している場合、_。countByメソッドはこれを実行します。

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

このメソッドは配列でも機能します。

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

2

これが私の解決策です。私の前にすでにたくさんの解決策が投稿されています。しかし、私はここで私の見解を共有するのが大好きです。

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

ここに私のREPLがあります


2

最速の方法はインデックス演算子を介しているようです:

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

またはプロトタイプ関数として:

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

以下は、正規表現を使用して長さをテストします。testexは、16以上の連続した非コンマ文字がないことを保証します。テストに合格すると、文字列の分割に進みます。コンマの数え方は、トークンから1を引いた数と同じくらい簡単です。

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

string.split(desiredCharecter).length-1はどうですか?

例:

var str = "人生は元気ですか"; var len = str.split( "h")。length-1; 上記の文字列の文字「h」にカウント2を与えます。


1

私はNode.js v.6.0.0を使用していますが、最も速いのはインデックス付きのものです(Lo Sauerの回答の3番目の方法)。

2つ目は次のとおりです。

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


1

これは、splitメソッドとreplaceメソッドとほぼ同じ速さで、正規表現メソッド(Chromeの場合)よりも少し高速です。

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

1

Node v7.4を使用してrepl.itで非常に迅速でダーティなテストを行いました。単一の文字の場合、標準のforループが最も高速です。

いくつかのコード

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

数回の実行の結果

 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

そこには:

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

整数でも動作します!


0

私の解決策:

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

これは、一致しないString.prototype.matchリターンとしては機能しませんnull。つまり、length属性を持つオブジェクトへの参照はありません。言い換えると、String.prototype.match.call('willnotwork', /yesitwill/) === null
Lorenz Lo Sauerが

0

Leo Sauersの5番目の方法は、文字が文字列の先頭にある場合に失敗します。例えば

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

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

フィルター関数ブールは0に対してfalseを与えるため、3ではなく2を返します。

その他の可能なフィルター機能:

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

0

これは古い質問かもしれませんが、JavaScriptの低レベルの初心者向けの簡単な解決策があります。

初心者として、私はこの質問のいくつかの解決策しか理解できなかったので、2つの入れ子になったFORループを使用して、文字列内の他のすべての文字に対して各文字をチェックし、カウントを増やしました見つかった各文字の変数をました。

各プロパティキーが文字で、値がstring(count)に出現する回数である新しい空白のオブジェクトを作成しました。

関数の例:-

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

以下の解決策は非常に短く、非常に高速で、非常に長い文字列を処理でき、複数の文字検索をサポートでき、エラーを証明でき、空の文字列検索を処理できると思います。

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

使用例:

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

上記のコードは、Jakub Wawszczykの主要なパフォーマンスバグを修正します。コードは、indexOfが何もないと彼が関数入力パラメーターを指定するのを忘れたためにバージョン自体が機能していないと言った後でも、一致を探し続けます。


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

JavaScriptでは、上記のコードを使用して、文字列内の文字の出現を取得できます。


0

ラムダjsを使った私の解決策:

const testString = 'somestringtotest'

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

countLetters(testString)

REPLへのリンク。


0

この関数は、文字列strをパラメーターとして取り、文字列内の一意の各文字の出現をカウントします。結果は、各文字のキーと値のペアになります。

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;

} 

質問の2番目の部分を忘れてしまった:「各文字列、つまりstr1またはstr2またはstr3またはstr4が15文字を超えてはならないことも検証する必要があります。」
Maxime Launois
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.