はじめに

前回、PCRE Subsignatureをパースした。

あとはまとめるだけのつもりだったが、Image Fuzzy Hashが残っていた。あとワイルドカードとか細々した奴…

とりあえずImage Fuzzy Hashから。

Special Subsignature Types

Image Fuzzy Hash

びっくりするくらいパースが簡単で助かるね。

fuzzy_img#<hash>#<dist>

distはハミング距離で、これは省略可能らしい。今の所0より大きい値はサポートされていないので、Defaultを0にする。

use nom::{
    bytes::complete::{tag, take_while1},
    character::complete::{char, digit1},
    combinator::{map_res, opt},
    sequence::preceded,
    IResult,
};
use std::str::FromStr;

const DEFAULT_DISTANCE: usize = 0;

#[derive(Debug, PartialEq, Eq)]
pub struct FuzzyImg<'f> {
    pub hash: &'f str,
    pub distance: usize,
}

fn parse_fuzzy_img(input: &str) -> IResult<&str, FuzzyImg> {
    let (input, _) = tag("fuzzy_img#")(input)?;
    let (input, hash) = take_while1(|c: char| c.is_alphanumeric())(input)?;

    let (input, distance) = opt(preceded(
        char('#'),
        map_res(digit1, |dist_str: &str| usize::from_str(dist_str)),
    ))(input)?;

    Ok((
        input,
        FuzzyImg {
            hash,
            distance: distance.unwrap_or(DEFAULT_DISTANCE),
        },
    ))
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn parse_fuzzy_img_example_with_distance() {
        let parsed = parse_fuzzy_img("fuzzy_img#af2ad01ed42993c7#0").unwrap();
        assert_eq!(
            FuzzyImg {
                hash: "af2ad01ed42993c7",
                distance: 0
            },
            parsed.1
        );
    }

    #[test]
    fn parse_fuzzy_img_example_without_distance() {
        let parsed = parse_fuzzy_img("fuzzy_img#af2ad01ed42993c7").unwrap();
        assert_eq!(
            FuzzyImg {
                hash: "af2ad01ed42993c7",
                distance: 0
            },
            parsed.1
        );
    }
}

いい感じ。あと残っているのはPEのIVとアイコンに関する奴。それとHexのワイルドカード類。

終わりに

この記事はn01e0 Advent Calendar 2024の16日目の記事とします。

M@STER EXPOマジで最高でした。