LoginSignup
0
0

More than 1 year has passed since last update.

再帰検索なるものをやってみた

Last updated at Posted at 2019-12-02

つくってみた

Search.java
package search;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

public class Search {
	
	public static void main(String[] args) {
		
		String path = "C:\\Users\\";
		String word = "\\pool\\plugins\\";

		if (validate(path, word)) {
			// 入力値OKの場合に再帰検索
			search(path, word);
		}
		
		System.out.println("おわり");
	}
	
	/**
	 * ディレクトリ内を文字列で検索する.
	 * <p>
	 * 検索文字列を含む名前のファイル及びディレクトリの絶対パスを出力しつつ
	 * 再帰的に検索していく.
	 * 
	 * @param dir 検索対象のディレクトリ
	 * @param word 検索する文字列
	 * @throws IOException なんかひらけなかったとき
	 */
	private static void search(String dir, String word) {
		
		// ディレクトリ内の一覧を取得
		File[] directory = new File(dir).listFiles();
		
		// オブジェクトが存在しない場合, 処理を終了 
		if (directory == null) {
			return;
		}
		
		// 検索ワードを含んでいるものは絶対パスを出力
		Arrays.stream(directory).map(File::getName).filter(file -> isMatch(file, word))
				.forEach(file -> System.out.println(dir + "\\" + file));
		
		// ディレクトリを再帰検索
		Arrays.stream(directory).filter(File::isDirectory).map(File::getPath)
				.forEach(nextPath -> search(nextPath, word));
	}
	
	/**
	 * 単語検索.
	 * <p>
	 * 検索する文字を空白で区切り, OR検索する.
	 * <p>
	 * ファイル名が単語のいずれかを含めば{@code ture}
	 * 
	 * @param file ファイル名
	 * @param word 検索する単語
	 * @return 含めば{@code true}
	 */
	private static boolean isMatch(String file, String word) {
		
		List<String> stock = new LinkedList<>();
		
		// 空白文字で区切る
		for (String e : word.split(" ")) {
			// \\で区切る
			for (String e2 : e.split("\\\\")) {
				stock.add(e2);
			}
		}
		
		// 文字列を含む場合はtrue
		return stock.stream().map(String::trim).anyMatch(spell -> file.contains(spell));
	}

	/**
	 * nullブランクのチェック.
	 * <ul>
	 * チェック内容
	 * <li>引数が{@code null}の配列の場合{@code false}
	 * <li>引数の要素すべてに対して以下を満たしたら{@code true}
	 * <ul>
	 * <li>{@code null}でない
	 * <li>{@code String}変換したとき空文字でない
	 * <li>{@code String}変換したとき空白文字でない
	 * </ul>
	 * 一つでも引っかかったら{@code false}
	 * </ul>
	 * 
	 * @param obj {@code null}を許容するオブジェクト配列
	 * @return チェック可否
	 */
	private static boolean validate(Object...obj) {
		return obj == null ? false
				: Arrays.stream(obj)
						.filter(Objects::nonNull)
						.map(Object::toString)
						.filter(nonEmpty)
						.filter(nonBlank)
						// すべてOKならtrue
						.count() == obj.length ? true : false;
	}
	
	/** 空文字でなければ真 */
	private static final Predicate<String> nonEmpty = str -> !str.equals("");
	
	/** 空白のみでなければ真 */
	private static final Predicate<String> nonBlank = v -> v != null && !v.equals("")
			&& Arrays.stream(v.split("")).anyMatch(x -> !x.equals(" ") && !x.equals(" "));
}

出力がコンソールなのが安っぽいですが
空白区切りで複数単語のOR検索
まぁ検索処理もちょっと適当なのでisMatchメソッドのとこはあんま突っ込まないで下さい。。
単にString.containsでもよかったんですがなんかwebシステムとかならいろいろ工夫が必要かなと

validateの部分も今回の処理に合わせたので汎用性があるとは言えないかもです

ということで本題

search.java
	/**
	 * ディレクトリ内を文字列で検索する.
	 * <p>
	 * 検索文字列を含む名前のファイル及びディレクトリの絶対パスを出力しつつ
	 * 再帰的に検索していく.
	 * 
	 * @param dir 検索対象のディレクトリ
	 * @param word 検索する文字列
	 */
	private static void search(String dir, String word) {
		
		// ディレクトリ内の一覧を取得
		File[] directory = new File(dir).listFiles();
		
		// オブジェクトが存在しない場合, 処理を終了 
		if (directory == null) {
			return;
		}
		
		// 検索ワードを含んでいるものは絶対パスを出力
		Arrays.stream(directory).map(File::getName).filter(file -> isMatch(file, word))
				.forEach(file -> System.out.println(dir + "\\" + file));
		
		// ディレクトリを再帰検索
		Arrays.stream(directory).filter(File::isDirectory).map(File::getPath)
				.forEach(nextPath -> search(nextPath, word));
	}

再帰検索のところおもしろいですねこれ

一覧からディレクトリのものを探し
パスを取得し
それを引数としてまた同じことする

途中でreturn文がないと無限ループになるわけですが
whileを使わないwhile文とでもいうのでしょうか

自分で自分を呼ぶって、なにこれめっちゃ面白い!

0
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
0
0