1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaAdvent Calendar 2024

Day 22

Javaで学ぶアルゴリズム -文字列探索(力任せ法)

Posted at

文字列探索(力任せ法)

力まかせ探索(ちからまかせたんさく、英: Brute-force search)またはしらみつぶし探索(英: Exhaustive search)は、単純だが非常に汎用的な計算機科学の問題解決法であり、全ての可能性のある解の候補を体系的に数えあげ、それぞれの解候補が問題の解となるかをチェックする方法である。

線形探索を拡張したアルゴリズムになるので、素朴法とか単純法とかとも呼ばれたりするようです。

実行環境

  • JUnit 5
  • Java 8

テストコード

BruteForceSearchTest.java
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

public class BruteForceSearchTest {

	private String text;

	@BeforeEach
	public void setUp() {
		text = "これはテストです。This is a test. もう一度テストします。";
	}

	@DisplayName("パターンがテキスト内に存在する場合")
	@Nested
	class PatternExists {

		@DisplayName("パターンがテキストの最初に存在する場合、0が返ること")
		@Test
		void testPatternExistsAtBeginning() {
			assertThat(BruteForceSearch.bruteForceSearch(text, "これ"), is(0));
		}

		@DisplayName("パターンがテキストの中間に存在する場合、その位置が返ること")
		@Test
		void testPatternExistsInMiddle() {
			assertThat(BruteForceSearch.bruteForceSearch(text, "test"), is(19));
		}

		@DisplayName("パターンがテキストの最後に存在する場合、その位置が返ること")
		@Test
		void testPatternExistsAtEnd() {
			assertThat(BruteForceSearch.bruteForceSearch(text, "します"), is(32));
		}

		@DisplayName("パターンがテキストに複数存在する場合、最初の位置を返すこと")
		@Test
		public void testPatternExistsMultipleTimes() {
			assertThat(BruteForceSearch.bruteForceSearch(text, "テスト"), is(3));
		}

		@DisplayName("パターンが空の場合、0が返ること")
		@Test
		void testPatternIsEmpty() {
			assertThat(BruteForceSearch.bruteForceSearch(text, ""), is(0));
		}

		@DisplayName("テキストとパターンが共に空の場合、0が返ること")
		@Test
		void testBothTextAndPatternEmpty() {
			assertThat(BruteForceSearch.bruteForceSearch("", ""), is(0));
		}
	}

	@DisplayName("パターンがテキスト内に存在しない場合")
	@Nested
	class PatternNotExists {
		@DisplayName("パターンがテキストに存在しない場合、-1が返ること")
		@Test
		void testPatternNotExists() {
			assertThat(BruteForceSearch.bruteForceSearch(text, "成功"), is(-1));
		}

		@DisplayName("パターンの文字列の長さがテキストよりも大きい場合、-1が返ること")
		@Test
		void testPatternLongerThanText() {
			String longPattern = "これはテストです。This is a test. もう一度テストします。失敗";
			assertThat(BruteForceSearch.bruteForceSearch(text, longPattern), is(-1));
		}

		@DisplayName("テキストが空の場合、-1が返ること")
		@Test
		void testTextIsEmpty() {
			assertThat(BruteForceSearch.bruteForceSearch("", "テスト"), is(-1));
		}
	}

	@DisplayName("例外が投げられる場合")
	@Nested
	class ExceptionThrown {
		@DisplayName("パターンがnullの場合、NPEが投げられること")
		@Test
		void testPatternIsNull() {
			assertThrows(NullPointerException.class, () -> {
				BruteForceSearch.bruteForceSearch(text, null);
			});
		}

		@DisplayName("テキストがnullの場合、NPEが投げられること")
		@Test
		void testTextIsNull() {
			assertThrows(NullPointerException.class, () -> {
				BruteForceSearch.bruteForceSearch(null, "テスト");
			});
		}
	}
}

文字列探索(力任せ法)アルゴリズム

BruteForceSearch.java
public class BruteForceSearch {

	/**
	 * 力任せ法を用いて、テキスト文字列内でパターン文字列が最初に出現する箇所を探す
	 * @param text 検索対象のテキスト
	 * @param pattern 検索したいパターン
	 * @return パターンがテキスト内で最初に出現する開始インデックス(見つからない場合は-1)
	 */
	public static int bruteForceSearch(String text, String pattern) {
		int textIndex = 0;
		int patternIndex = 0;

		while (textIndex != text.length() && patternIndex != pattern.length()) {
			if (text.charAt(textIndex) == pattern.charAt(patternIndex)) {
				// 文字が一致する場合、次の位置を比較
				textIndex++;
				patternIndex++;
			} else {
				// 不一致の場合、テキストのインデックスを右にシフト
				textIndex = textIndex - patternIndex + 1;
				patternIndex = 0;
			}
		}
		if (patternIndex == pattern.length()) {
			return textIndex - patternIndex;
		}
		return -1;
	}
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?