Java: 文字列内の単語の出現回数を数える

概要

文字列内の単語の出現回数を数えるのはかなり簡単な作業ですが、それにはいくつかの方法があります。 通常、手作業を実行したくない場合、つまり検索スペースが大きい場合は、自動化されたツールを使用する必要があるため、方法の効率も考慮する必要があります。

このガイドでは、Java で文字列内の単語の出現回数をカウントする方法を学習します。

String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";

の出現回数を検索します。 targetWord、使用して String.split(), Collections.frequency() および正規表現。

文字列内の単語の出現回数をカウントする String.split()

文字列内の対象単語の出現をカウントする最も簡単な方法は、単語ごとに文字列を分割し、配列を反復処理して、 wordCount 各試合で。 単語の前後に何らかの句読点がある場合に注意してください。 wants. 文末 – 単純な単語レベルの分割では正しく処理されます wants および wants. 別の言葉として!

これを回避するには、文からすべての句読点を簡単に削除できます それを分割する:

String[] words = searchText.replaceAll("p{Punct}", "").split(" ");

int wordCount = 0;
for (int i=0; i < words.length; i++)
    if (words[i].equals(targetWord))
        wordCount++;
System.out.println(wordCount);

for ループでは、配列を単純に繰り返し処理し、各インデックスの要素が targetWord. そうであれば、 wordCount、実行の最後に、次を出力します。

2

文字列内の単語の出現回数をカウントする コレクション.frequency()

  Collections.frequency() メソッドは、単純な for ループし、両方の ID (オブジェクトかどうか) をチェックします。 is 別のオブジェクト) と同等性 (そのオブジェクトの質的特徴に応じて、オブジェクトが別のオブジェクトと等しいかどうか)。

  frequency() メソッドは、検索するリストとターゲット オブジェクトを受け入れ、他のすべてのオブジェクトに対しても機能します。動作は、オブジェクト自体の実装方法によって異なります。 equals(). 文字列の場合、 equals() をチェックします 文字列の内容:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

ここでは、から取得した配列を変換しました split() Javaに ArrayList、ヘルパーを使用して asList() の方法 Arrays クラス。 リダクション操作 frequency() の頻度を示す整数を返します targetWord リストに表示され、結果は次のようになります。

2

を使用した文字列内の単語の出現 Matcher (正規表現 – RegEx)

最後に、正規表現を使用してパターンを検索し、一致したパターンの数をカウントできます。 正規表現はこのために作成されているため、このタスクには非常に自然に適合します。 Java では、 Pattern クラスは、正規表現を表現およびコンパイルするために使用され、 Matcher クラスは、パターンを見つけて一致させるために使用されます。

RegEx を使用すると、句読点の不変性を式自体にコーディングできるため、文字列を外部でフォーマットしたり、句読点を削除したりする必要はありません。これは、別の変更されたバージョンをメモリに保存するとコストがかかる可能性がある大きなテキストに適しています。

Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));

Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);

int wordCount = 0;
while (matcher.find())
    wordCount++;

System.out.println(wordCount);

これも結果として:

2

効率ベンチマーク

それで、どれが最も効率的ですか? 小さなベンチマークを実行してみましょう。

int runs = 100000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithSplit(searchText, targetWord);
}

long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
  for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithCollections(searchText, targetWord);
}

long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithRegex(searchText, targetWord);
}

long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));

各メソッドは 100000 回実行されます (数値が大きいほど、大数の法則により、偶然による分散と結果が低くなります)。 このコードを実行すると、次のようになります。

Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds

しかし、検索を大きくして計算コストを高くするとどうなるでしょうか? 合成文を生成しましょう:

List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();

for (int i = 0; i < 100; i++) {
    searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);

これにより、次の内容の文字列が作成されます。

hello world hello world hello world hello ...

ベストプラクティス、業界で認められた標準、および含まれているチートシートを含む、Gitを学習するための実践的で実用的なガイドを確認してください。 グーグルGitコマンドを停止し、実際に 学ぶ それ!

ここで、「hello」または「world」のいずれかを検索すると、前の XNUMX つよりも多くの一致が得られます。 私たちの方法は現在、ベンチマークでどのように機能していますか?

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

これで、配列の分割が最速になりました! 一般に、ベンチマークはさまざまな要因 (検索スペース、ターゲット ワードなど) に依存し、個人のユース ケースはベンチマークとは異なる場合があります。

アドバイス: 独自のテキストでメソッドを試し、時間を記録して、最も効率的で洗練されたものを選択してください。

まとめ

この短いガイドでは、Java の文字列でターゲット単語の出現回数をカウントする方法を調べました。 文字列を分割し、単純なカウンターを使用することから始めました。 Collections ヘルパー クラス、そして最後に正規表現を使用します。

最後に、メソッドのベンチマークを行い、パフォーマンスが線形ではなく、検索スペースに依存することに気付きました。 多くの一致がある長い入力テキストの場合、配列の分割が最もパフォーマンスが高いようです。 XNUMX つの方法をすべて自分で試して、最もパフォーマンスの高い方法を選択してください。

タイムスタンプ:

より多くの スタックアバス