文字列に部分文字列が含まれているかどうかを確認します

1. 概要

このチュートリアルでは、_String_にサブストリングが含まれているかどうかを確認するいくつかの方法を確認し、それぞれのパフォーマンスを比較します。

2. String.indexOf

最初に_String.indexOf_メソッドを使用してみましょう。 * HTTPS://www.baeldung.com/string/index-of [_indexOf_]私たちのストリングが発見されるか、または-1、それが全く見つからない場合は最初の位置を与えます*。
「Rhap」を検索すると、9が返されます。
Assert.assertEquals(9, "Bohemian Rhapsodyan".indexOf("Rhap"));
「rhap」を検索すると、大文字と小文字が区別されるため、*-1が返されます。*
Assert.assertEquals(-1, "Bohemian Rhapsodyan".indexOf("rhap"));
Assert.assertEquals(9, "Bohemian Rhapsodyan".toLowerCase().indexOf("rhap"));
_substring_“ an”を検索すると、最初の出現を返すため6を返すことに注意することも重要です。
Assert.assertEquals(6, "Bohemian Rhapsodyan".indexOf("an"));

3. String.contains

次に、String.contains _を試してみましょう。 * https://www.baeldung.com/string/contains [_contains_]は、_String_全体で部分文字列を検索し、見つかった場合は_true_を、それ以外の場合は_false_を返します。*
この例では、「Hey」が見つかったため、_contains_は_true_を返します。
Assert.assertTrue("Hey Ho, let's go".contains("Hey"));
文字列が見つからない場合、_contains_は_false_を返します。
Assert.assertFalse("Hey Ho, let's go".contains("jey"));
最後の例では、* _ St​​ring.contains_では大文字と小文字が区別されるため、「hey」は見つかりません。*
Assert.assertFalse("Hey Ho, let's go".contains("hey"));
Assert.assertTrue("Hey Ho, let's go".toLowerCase().contains("hey"));
興味深い点は、* _ contains_が内部で_indexOf_ *を呼び出して、_substring_が含まれているかどうかを知ることです。

4. StringUtils.containsIgnoreCase

3番目のアプローチは、https://commons.apache.org/proper/commons-lang/ [Apache Commons Lang]ライブラリ**の__ * StringUtils#* __ ** _ containsIgnoreCase_を使用することです。
Assert.assertTrue(StringUtils.containsIgnoreCase("Runaway train", "train"));
Assert.assertTrue(StringUtils.containsIgnoreCase("Runaway train", "Train"));
_substring_が_String_に含まれているかどうかをチェックし、大文字小文字を無視することがわかります*。 そのため、「暴走列車」内で「Trai」と「trai」を検索すると、https://www.baeldung.com/string-processing-commons-lang [_containsIgnoreCase_]が_true_を返します。
このアプローチは、以前のアプローチほど効率的ではありません*、ケースを無視するには追加の時間がかかります。 _containsIgnoreCase_は、すべての文字を内部的に大文字に変換し、元の文字ではなく変換された文字を比較します。

5. _Pattern_の使用

最後のアプローチは、正規表現で* _Pattern_を使用することです*。
Pattern pattern = Pattern.compile("(?<!\\S)" + "road" + "(?!\\S)");
*最初にlink:/regular-expressions-java[_Pattern_]を構築する必要があり、次に_Matcher_を作成する必要があり、最後に_find_メソッドがあるかどうかを確認できます。部分文字列の出現または非出現:*
Matcher matcher = pattern.matcher("Hit the road Jack");
Assert.assertTrue(matcher.find());
たとえば、最初に_find_ firstを実行すると、文字列「Hit the road Jack」内に「road」という単語が含まれているため、_true_が返されますが、同じ単語を検索しようとすると文字列「これ以上戻ってこないか」は、_false:_を返します。
Matcher matcher = pattern.matcher("and don't you come back no more");
Assert.assertFalse(matcher.find());

6. 性能比較

link:/java-microbenchmark-harness[_Java Microbenchmark Harness_](JMH)と呼ばれるオープンソースのマイクロベンチマークフレームワークを使用して、実行の観点から最も効率的な方法を決定します。時間。

6.1. ベンチマーク設定

すべてのJMH​​ベンチマークと同様に、ベンチマークを実行する前に特定のものを配置するために、_setup_メソッドを記述することができます。
@Setup
public void setup() {
    message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
      "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
      "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " +
      "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " +
      "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
      "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " +
      "mollit anim id est laborum";
    pattern = Pattern.compile("(?<!\\S)" + "eiusmod" + "(?!\\S)");
}
_setup_メソッドでは、_message_フィールドを初期化しています。 これをさまざまな検索実装のソーステキストとして使用します。
また、後でベンチマークの1つで使用するために、_pattern_を初期化しています。

6.2. _String.indexOf_ベンチマーク

最初のベンチマークでは、_indexOf_を使用します。
@Benchmark
public int indexOf() {
    return message.indexOf("eiusmod");
}
_message_変数のどの位置に「eiusmod」が存在するかを検索します。

6.3. String.contains _ベンチマーク

2番目のベンチマークでは、_contains_を使用します。
@Benchmark
public boolean contains() {
    return message.contains("eiusmod");
}
_message_値_contains_「eiusmod」であるかどうか、以前のベンチマークで使用されたものと同じ_substring_を見つけようとします。

6.4. _StringUtils.containsIgnoreCase_ベンチマーク

3番目のベンチマークでは、_StringUtils#containsIgnoreCase_を使用します。
@Benchmark
public boolean containsStringUtilsIgnoreCase() {
    return StringUtils.containsIgnoreCase(message, "eiusmod");
}
前のベンチマークと同様に、_message_値の_substring_を検索します。

6.5. _Pattern_ベンチマーク

最後のベンチマークでは、_Pattern_を使用します。
@Benchmark
public boolean searchWithPattern() {
    return pattern.matcher(message).find();
}
_setup_メソッドで初期化されたパターンを使用して_Matcher_を作成し、以前と同じサブストリングを使用して_find_メソッドを呼び出すことができます。

6.6. ベンチマーク結果の分析

*ベンチマーク結果をナノ秒単位で評価していることに注意することが重要です。
JMHテストを実行した後、それぞれにかかった平均時間を確認できます。
  • contains:14.736 ns

  • indexOf:14.200 ns

  • containsStringUtilsIgnoreCase:385.632 ns

  • searchWithPattern:1014.633 ns

    _indexOf_メソッドは最も効率的なメソッドであり、_contains_が続きます。 *内部で_indexOf_を使用しているため、_contains_に時間がかかったのは理にかなっています。*
    _containsStringUtilsIgnoreCase_は、大文字と小文字が区別されないため、前のものと比較して余分な時間がかかりました。
    _searchWithPattern_は、最後の時間よりもさらに長い平均時間を費やし、* _ Pattern__sを使用することがこのタスクの最悪の選択肢であることを証明します。*

7. 結論

この記事では、_String内の部分文字列を検索するさまざまな方法を検討しました。_また、さまざまなソリューションのパフォーマンスのベンチマークも行いました。
いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/java-strings-2[GitHub上]で入手できます。