[Rust] Path に glob がなかったので外部クレートの glob と globmatch を使ってみた


はじめに

ファイルを収集するとき Ruby では Pathname.glob があった。
でも Rust の Path には glob がなくてがっかりだった。
そこで外部クレートで見つけた次の2つを使ってみる。

まずディレクトリ構成は次のようになっている。

$ exa -T a
a
└── b
   └── c
      ├── 1.png
      ├── 2.png
      └── 3.PNG

ところで──この exa は Rust 製の ls 風ツールで、なんとパスに日本語が含まれていても化けずにツリー表示できるのだ。
普通の tree コマンドは -N オプションをつけないと日本語表示されなかったりする。
なお、exa は cargo install exa でインストールできる。

glob 編

簡単な使い方

use glob::glob;

let files = glob("a/**/*.png")
    .unwrap()
    .map(|e| e.unwrap())
    .collect::<Vec<_>>();

println!("{:?}", files);
// >> ["a/b/c/1.png", "a/b/c/2.png"]

3.PNG が出てきていないのは大小文字を区別するようになっているから。
そういうときは a/**/*.{png,PNG} と書けば PNG にもマッチするもんだけど動かなかった (なんで?)

大小文字の区別をやめる

use glob::glob_with;
use glob::MatchOptions;

let mut options = MatchOptions::new();
options.case_sensitive = false; // false:大小文字の区別をしない

let files = glob_with("a/**/*.png", options)
    .unwrap()
    .map(|e| e.unwrap())
    .collect::<Vec<_>>();

println!("{:?}", files);
// >> ["a/b/c/1.png", "a/b/c/2.png", "a/b/c/3.PNG"]

case_sensitivefalse にしたことで png でも PNG にマッチするようになったのがわかる。

できれば case_sensitive: false を初期値にしといてほしかった(小声)

globmatch 編

簡単な使い方

let files = globmatch::Builder::new("a/**/*.{png,PNG}")
    .build(".")
    .unwrap()
    .into_iter()
    .flatten()
    .collect::<Vec<_>>();

// files は PathBuf の配列
println!("{:?}", files);
// >> ["./a/b/c/2.png", "./a/b/c/3.PNG", "./a/b/c/1.png"]

こちらも大小文字区別ありが初期値となっているけど a/**/*.{png,PNG} と書ける!
その点で言えばこっちの方が使いやすそう。