Created
August 19, 2024 14:42
-
-
Save kujirahand/843c34e789af18551c01f22f6cdfab90 to your computer and use it in GitHub Desktop.
ワイルドカードをRustで実装したもの
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fn main() { | |
// 「ab?.txt」が「abc.txt」にマッチするか --- (*1) | |
println!("{}", is_match("ab?.txt", "abc.txt")); // true | |
} | |
// ワイルドカードのパターン「?」を使った文字列マッチング --- (*2) | |
fn is_match(pattern: &str, target: &str) -> bool { | |
// &strをVec<char>に変換してis_match_sliceを呼び出す | |
let pattern: Vec<char> = pattern.chars().collect(); | |
let target: Vec<char> = target.chars().collect(); | |
is_match_slice(&pattern, &target) | |
} | |
// ワイルドカードのパターンを使った文字列マッチング --- (*3) | |
fn is_match_slice(pattern: &[char], target: &[char]) -> bool { | |
let mut ip = 0; | |
let mut it = 0; | |
// 1文字ずつ順に比較していく --- (*4) | |
while ip < pattern.len() && it < target.len() { | |
if pattern[ip] == '*' { // 0文字以上の任意文字にマッチ --- (*5) | |
ip += 1; // ワイルドカードをスキップ | |
// ワイルドカードの次の文字が一致するまで繰り返す | |
for i in it..target.len() { | |
// 新たなスライスを作って再帰的にマッチングを行う | |
let sub_pattern = &pattern[ip..]; | |
let sub_target = &target[i..]; | |
if is_match_slice(sub_pattern, sub_target) { | |
return true; | |
} | |
} | |
continue; | |
} | |
if pattern[ip] == '?' { // 任意の1文字にマッチ --- (*6) | |
ip += 1; | |
it += 1; | |
continue; | |
} | |
if pattern[ip] == target[it] { // 文字が一致 --- (*7) | |
ip += 1; | |
it += 1; | |
continue; | |
} | |
return false; // マッチしない | |
} | |
// パターンも対象も末尾まで到達した場合にtrueを返す --- (*8) | |
ip == pattern.len() && it == target.len() | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn test() { | |
// いろいろなパターンを試してみる --- (*9) | |
assert_eq!(is_match("ab?.txt", "abc.txt"), true); | |
assert_eq!(is_match("a*.txt", "abc.txt"), true); | |
assert_eq!(is_match("*.txt", "abc.txt"), true); | |
assert_eq!(is_match("a?g.txt", "abcdefg.txt"), false); | |
assert_eq!(is_match("a*g.txt", "abcdefg.txt"), true); | |
assert_eq!(is_match("a*b*g.txt", "abcdefg.txt"), true); | |
assert_eq!(is_match("*efg.txt", "abcdefg.txt"), true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment