😺

regexを用いたRustの正規表現取り扱いメモ

2024/04/24に公開


スクラップにメモしていたシリーズです。regexクレートで正規表現を取り扱う方法を調べた結果のメモです。[regex "1.10.4"]

前提

Cargo.toml
[dependencies]
regex = "1.10.4"

サンプルコード

use itertools::Itertools;
use regex::{RegexBuilder, Regex, Match, Captures};

fn haystack() -> &'static str {
"2024-04-1823
2020-12-0700100-00-00"
}
fn main() {
    let haystack = haystack();
    let pattern = r"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
    let re: Regex = RegexBuilder::new(pattern) // ?<foo> is name tag for captures
        .unicode(true) // default=true; false should be used to ascii only string
        .case_insensitive(false) // default=false
        .multi_line(false) // default=false; true changes behavior of "^" and "$"
        .dot_matches_new_line(false) // default=false
        .build()
        .unwrap();

    // exist pattern or not
    assert!(re.is_match(haystack));

    // get pattern blocks
    re.find_iter(haystack).for_each(|x: Match<'_>| { // find() is matched only one time
        println!("{} {}", x.start(), x.as_str());
        // 0 2024-04-18
        // 13 2020-12-07
        // 24 0100-00-00
    });

    // get parts of pattern
    let expand_format = "EXPAND:$year$month$day";
    re.captures_iter(haystack).for_each(|x: Captures<'_>| { // captures() is matched only one time
        let (full, [year, _, _]) = x.extract();
        let mut expand = String::new();
        x.expand(expand_format, &mut expand);
        println!("Match: {}, y:{}, m:{}, d:{}, {}",
            full, year, x.name("month").unwrap().as_str(), x.get(3).unwrap().as_str(), expand);
            // Match: 2024-04-18, y:2024, m:04, d:18, EXPAND:20240418
            // Match: 2020-12-07, y:2020, m:12, d:07, EXPAND:20201207
            // Match: 0100-00-00, y:0100, m:00, d:00, EXPAND:01000000
    });

    // replace pattern, replace() is matched only one time
    assert_eq!(re.replace_all(&haystack, "XYZ").lines().join("").as_str(), "XYZ23XYZ0XYZ");
    assert_eq!(re.replace_all(&haystack, "[$2/$day/${year}_$$]").lines().join("").as_str()
        ,"[04/18/2024_$]23[12/07/2020_$]0[00/00/0100_$]");

    // get not matched part
    println!("{:?}", re.split(haystack).collect::<Vec<_>>()); // ["", "23\n", "0", ""]
}

メモ

  • 2つ以上の正規表現を一度に検査したい場合、RegexSetを使用する
    • ただし以下用途にのみ利用できる
      • 正規表現セット内にマッチするかどうか
      • マッチする場合、どの正規表現にマッチするか

参考文献

Discussion