文字列に複数のキーワードが含まれているかどうかを確認する

1. 前書き

このクイックチュートリアルでは、*文字列内の複数の単語を検出する方法について説明します*。

2. 私たちの例

文字列があるとしましょう:
String inputString = "hello there, Baeldung";
私たちのタスクは、__inputString ___に_âhelloâ_と_âbelœungâ€_の単語が含まれているかどうかを調べることです。
それでは、キーワードを配列に入れましょう。
String[] words = {"hello", "Baeldung"};
さらに、単語の順序は重要ではなく、一致は大文字と小文字を区別する必要があります。

*3. String.contains() *の使用

最初に、目標を達成するためにlink:/string/contains[_String.contains()_]メソッドを使用する方法を示します*。
キーワード配列をループして、_inputString:_内の各項目の出現を確認しましょう。
public static boolean containsWords(String inputString, String[] items) {
    boolean found = true;
    for (String item : items) {
        if (!inputString.contains(item)) {
            found = false;
            break;
        }
    }
    return found;
}
input_inputString_に指定された_item_が含まれている場合、_contains()_メソッドは_true_を返します。 文字列内にキーワードがない場合は、前方への移動を停止して、すぐに_false_を返すことができます。
*より多くのコードを記述する必要があるという事実にもかかわらず、このソリューションは単純なユースケースでは高速です。*

*4. String.indexOf() *を使用する

_String.contains()_メソッドを使用するソリューションと同様に、https://www.baeldung.com/string/index-of [_String.indexOf()_]を使用して「キーワードのインデックス」を確認できます。方法*。 そのためには、_inputString_とキーワードのリストを受け入れるメソッドが必要です。
public static boolean containsWordsIndexOf(String inputString, String[] words) {
    boolean found = true;
    for (String word : words) {
        if (inputString.indexOf(word) == -1) {
            found = false;
            break;
        }
    }
    return found;
}
_indexOf()_メソッドは、_inputString_内の単語のインデックスを返します。 テキストに単語がない場合、インデックスは-1になります。

5. 正規表現を使用する

ここで、https://www.baeldung.com/regular-expressions-java [正規表現]を使用して、単語と一致させましょう。 そのために、_Pattern_クラスを使用します。
まず、文字列式を定義しましょう。 2つのキーワードを一致させる必要があるため、2つの先読みを使用して正規表現ルールを作成します。
Pattern pattern = Pattern.compile("(?=.*hello)(?=.*Baeldung)");
そして一般的な場合:
StringBuilder regexp = new StringBuilder();
for (String word : words) {
    regexp.append("(?=.*").append(word).append(")");
}
その後、_matcher()_メソッドを使用してオカレンスを_find()_します。
public static boolean containsWordsPatternMatch(String inputString, String[] words) {

    StringBuilder regexp = new StringBuilder();
    for (String word : words) {
        regexp.append("(?=.*").append(word).append(")");
    }

    Pattern pattern = Pattern.compile(regexp.toString());

    return pattern.matcher(inputString).find();
}
ただし、*正規表現にはパフォーマンスコストがかかります。 検索する複数の単語がある場合、このソリューションのパフォーマンスは最適ではない可能性があります。*

*6. Java 8および_List_ *の使用

そして最後に、Java 8のlink:/java-8-streams-introduction[Stream API]を使用できます。 しかし、最初に、初期データでいくつかの小さな変換を行いましょう。
List<String> inputString = Arrays.asList(inputString.split(" "));
List<String> words = Arrays.asList(words);
次に、Stream APIを使用します。
public static boolean containsWordsJava8(String inputString, String[] words) {
    List<String> inputStringList = Arrays.asList(inputString.split(" "));
    List<String> wordsList = Arrays.asList(words);

    return wordsList.stream().allMatch(inputStringList::contains);
}
入力文字列にすべてのキーワードが含まれている場合、上記の操作パイプラインは_true_を返します。
または、* https://www.baeldung.com/java-collections [Collections framework] *の_containsAll()_メソッドを使用して、目的の結果を得ることができます。
public static boolean containsWordsArray(String inputString, String[] words) {
    List<String> inputStringList = Arrays.asList(inputString.split(" "));
    List<String> wordsList = Arrays.asList(words);

    return inputStringList.containsAll(wordsList);
}
ただし、この方法は単語全体に対してのみ機能します。 したがって、キーワードがテキスト内で空白で区切られている場合にのみ、キーワードが検出されます。

7. _Aho-Corasick_アルゴリズムの使用

簡単に言えば、* https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm [_Aho-Corasick_ algorithm]は、複数のキーワードを使用したテキスト検索用です*。 *検索するキーワードの数やテキストの長さに関わらず、_O(n)_時間の複雑さを持ちます。*
_pom.xml_にhttps://search.maven.org/search?q=g:org.ahocorasick%20a:ahocorasick[Aho-Corasickアルゴリズム依存関係]を含めましょう。
<dependency>
    <groupId>org.ahocorasick</groupId>
    <artifactId>ahocorasick</artifactId>
    <version>0.4.0</version>
</dependency>
まず、キーワードの_words_ arrayを使用してトライパイプラインを構築しましょう。 そのために、https://www.baeldung.com/trie-java [Trie]データ構造を使用します。
Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();
その後、キーワードを検索し、_emits_コレクションに結果を保存する_inputString_テキストを使用してパーサーメソッドを呼び出しましょう。
Collection<Emit> emits = trie.parseText(inputString);
そして最後に、結果を印刷すると:
emits.forEach(System.out::println);
キーワードごとに、テキスト内のキーワードの開始位置、終了位置、およびキーワード自体が表示されます。
0:4=hello
13:20=Baeldung
最後に、完全な実装を見てみましょう。
public static boolean containsWordsAhoCorasick(String inputString, String[] words) {
    Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();

    Collection<Emit> emits = trie.parseText(inputString);
    emits.forEach(System.out::println);

    boolean found = true;
    for(String word : words) {
        boolean contains = Arrays.toString(emits.toArray()).contains(word);
        if (!contains) {
            found = false;
            break;
        }
    }

    return found;
}
この例では、単語全体のみを探しています。 したがって、_inputString_だけでなく_âhellœBaeldungâ€_も一致させたい場合は、_Trie_ビルダーパイプラインから_onlyWholeWords()_属性を単に削除する必要があります。
さらに、同じキーワードに複数の一致がある可能性があるため、_emits_コレクションから重複する要素も削除することに注意してください。

8. 結論

この記事では、文字列内で複数のキーワードを見つける方法を学びました。 さらに、*コアJDKとAho-Corasick_ライブラリを使用して例を示しました。*
いつものように、この記事の完全なコードはhttps://github.com/eugenp/tutorials/tree/master/java-strings-2[on on GitHub]にあります。