1. 概要

このチュートリアルでは、Javaを使用して特定の文字列内の単語をカウントするさまざまな方法について説明します。

2. StringTokenizerを使用する

Javaで文字列内の単語をカウントする簡単な方法は、StringTokenizerクラスを使用することです。

assertEquals(3, new StringTokenizer("three blind mice").countTokens());
assertEquals(4, new StringTokenizer("see\thow\tthey\trun").countTokens());

StringTokenizer は、タブやキャリッジリターンなど、空白の処理を自動的に行うことに注意してください。

ただし、ハイフンなど、一部の場所では失敗する可能性があります。

assertEquals(7, new StringTokenizer("the farmer's wife--she was from Albuquerque").countTokens());

この場合、「妻」と「彼女」は別の単語にする必要がありますが、間に空白がないため、デフォルトでは失敗します。

幸い、StringTokenizerは別のコンストラクターと一緒に出荷されます。 区切り文字をコンストラクターに渡して、上記を機能させることができます。

assertEquals(7, new StringTokenizer("the farmer's wife--she was from Albuquerque", " -").countTokens());

これは、CSVファイルのようなからの文字列内の単語をカウントしようとするときに便利です:

assertEquals(10, new StringTokenizer("did,you,ever,see,such,a,sight,in,your,life", ",").countTokens());

したがって、 StringTokenizer は単純であり、ほとんどの方法でそこに到達します。

余分な馬力の正規表現が私たちに何を与えることができるか見てみましょう。

3. 正規表現

このタスクで意味のある正規表現を作成するには、単語と見なすものを定義する必要があります。単語は文字で始まり、スペース文字または句読点で終わります。

これを念頭に置いて、文字列が与えられた場合、スペースと句読点に遭遇するすべてのポイントでその文字列を分割し、結果の単語を数えます。

assertEquals(7, countWordsUsingRegex("the farmer's wife--she was from Albuquerque"));

正規表現の力を確認するために、少し調べてみましょう。

assertEquals(9, countWordsUsingRegex("no&one#should%ever-write-like,this;but:well"));

StringTokenizer に区切り文字を渡すだけでこれを解決するのは実用的ではありません。これは、可能なすべての句読点をリストするために非常に長い区切り文字を定義する必要があるためです。

本当に多くのことをする必要はないことがわかりました、 正規表現を渡す [\ pP \ s && [^’]] +スプリットの方法クラスはトリックを行います

public static int countWordsUsingRegex(String arg) {
    if (arg == null) {
        return 0;
    }
    final String[] words = arg.split("[\pP\s&&[^']]+");
    return words.length;
}

正規表現 [\ pP \ s && [^’]] + 句読点またはスペースのいずれかの長さを検出し、アポストロフィ句読点を無視します。

正規表現の詳細については、Baeldungの正規表現を参照してください。

4. ループと文字列API

もう1つの方法は、検出された単語を追跡するフラグを設定することです。

新しい単語に遭遇したときにフラグをWORDに設定し、単語数を増やし、単語以外(句読点またはスペース文字)に遭遇したときにSEPARATORに戻ります。

このアプローチでは、正規表現で得られたのと同じ結果が得られます。

assertEquals(9, countWordsManually("no&one#should%ever-write-like,this but   well"));

句読点が実際には単語の区切り文字ではない特殊なケースに注意する必要があります。例:

assertEquals(6, countWordsManually("the farmer's wife--she was from Albuquerque"));

ここで必要なのは、アポストロフィ「”」は句読点ですが、「農家」を1つの単語として数えることです。

正規表現バージョンでは、正規表現を使用してキャラクターとして適格でないものを定義する柔軟性がありました。 しかし、独自の実装を作成しているので、この除外を別のメソッドで定義する必要があります。

private static boolean isAllowedInWord(char charAt) {
    return charAt == '\'' || Character.isLetter(charAt);
}

したがって、ここで行ったことは、すべての文字と合法的な句読点(この場合はアポストロフィ)を一言で許可することです。

これで、実装でこのメソッドを使用できます。

public static int countWordsManually(String arg) {
    if (arg == null) {
        return 0;
    }
    int flag = SEPARATOR;
    int count = 0;
    int stringLength = arg.length();
    int characterCounter = 0;

    while (characterCounter < stringLength) {
        if (isAllowedInWord(arg.charAt(characterCounter)) && flag == SEPARATOR) {
            flag = WORD;
            count++;
        } else if (!isAllowedInWord(arg.charAt(characterCounter))) {
            flag = SEPARATOR;
        }
        characterCounter++;
    }
    return count;
}

最初の条件は、単語に遭遇すると単語をマークし、カウンターをインクリメントします。 2番目の条件は、文字が文字でないかどうかをチェックし、フラグをSEPARATORに設定します。

5. 結論

このチュートリアルでは、いくつかのアプローチを使用して単語を数える方法を見てきました。 特定のユースケースに応じて、任意のものを選択できます。

いつものように、このチュートリアルのソースコードはGitHubにあります。