ren3 0.1.0

Do file renaming using regular expressions.
Documentation
use regex::{Error, Regex, RegexBuilder};

#[derive(Debug, PartialEq)]
pub enum ErrorKind {
    UnknownCommand(char),
    UnknownFlag(char),
    TooManySegments,
    NotEnoughSegments,
    RegexError(Error),
}

#[derive(Debug, PartialEq)]
pub struct RegexData {
    pattern_str: String,
    pub replace_str: String,
    pub flag_global: bool,
    flag_case_insensitive: bool,
}

impl RegexData {
    pub fn build_regex(&self) -> Result<Regex, ErrorKind> {
        RegexBuilder::new(&self.pattern_str)
            .case_insensitive(self.flag_case_insensitive)
            .build()
            .map_err(ErrorKind::RegexError)
    }
}

pub fn split_regex(expr: &str) -> Result<RegexData, ErrorKind> {
    let expr = expr.chars().collect::<Vec<_>>();
    if expr[0] != 's' {
        return Err(ErrorKind::UnknownCommand(expr[0]));
    }
    let delimiter = expr[1];

    let mut segments = vec![];
    let mut segment = vec![];

    let mut i = 2;
    while i < expr.len() {
        let c = expr[i];
        if c == '\\' {
            segment.push(expr[i + 1]);
            i += 1;
        } else if c == delimiter {
            segments.push(segment.iter().collect::<String>());
            segment.clear();
        } else {
            segment.push(c);
        }
        i += 1;
    }
    if !segment.is_empty() {
        segments.push(segment.iter().collect::<String>());
    }

    if segments.len() < 2 {
        return Err(ErrorKind::NotEnoughSegments);
    } else if segments.len() > 3 {
        return Err(ErrorKind::TooManySegments);
    }

    let mut ret = RegexData {
        pattern_str: segments[0].to_owned(),
        replace_str: segments[1].to_owned(),
        flag_global: false,
        flag_case_insensitive: false,
    };

    if segments.len() == 3 {
        for c in segments[2].chars() {
            match c {
                'i' => ret.flag_case_insensitive = true,
                'g' => ret.flag_global = true,
                _ => return Err(ErrorKind::UnknownFlag(c)),
            }
        }
    }

    Ok(ret)
}

#[cfg(test)]
mod tests {
    use crate::sedregex::*;

    #[test]
    fn test() {
        assert_eq!(
            Ok(RegexData {
                pattern_str: "123".to_string(),
                replace_str: "456".to_string(),
                flag_global: false,
                flag_case_insensitive: false,
            }),
            split_regex("s/123/456")
        );
    }
}