#![deny(missing_docs)]
mod command;
mod cow_appender;
mod regex_flags;
mod replace_command;
mod replace_data;
mod splitting_iter;
mod str_ext;
pub use crate::{regex_flags::RegexFlag, replace_command::ReplaceCommand};
use std::{
borrow::Cow,
fmt::{self, Display},
};
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
NotEnoughSegments,
UnknownCommand(String),
UnknownFlag(char),
RegexError(regex::Error),
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ErrorKind::*;
match self {
NotEnoughSegments => write!(
f,
"Parsing error: a given string doesn't have enough segments"
),
UnknownCommand(cmd) => write!(
f,
"Parsing error: unknown regex command '{}' has been detected",
cmd
),
UnknownFlag(flag) => write!(
f,
"Parsing error: unknown regex flag '{}' has been detected",
flag
),
RegexError(_err) => write!(f, "Parsing error: regex parsing/compiling error"),
}
}
}
impl std::error::Error for ErrorKind {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ErrorKind::NotEnoughSegments | ErrorKind::UnknownCommand(_) | ErrorKind::UnknownFlag(_) => None,
ErrorKind::RegexError(r) => Some(r),
}
}
}
pub fn find_and_replace<I>(text: &str, commands: I) -> Result<Cow<str>, ErrorKind>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
commands
.into_iter()
.try_fold(Cow::Borrowed(text), |text, cmd| {
let replacer = ReplaceCommand::new(cmd.as_ref())?;
Ok(replacer.execute(text))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replace_simple() {
let input = "a very short text";
let commands = &[r"s/\w+/_/g"];
let expected = "_ _ _ _";
let actual = find_and_replace(input, commands).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn replace_simple2() {
let input = r"a$ very%% sh@ort! tex\w+t";
let commands = &[r"s/\w+/_/g"];
let expected = r"_$ _%% _@_! _\_+_";
let actual = find_and_replace(input, commands).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn replace_simple3() {
let input = r"a$ very%% sh@ort! tex\w+t";
let commands = &[r"s/\w+/_/"];
let expected = r"_$ very%% sh@ort! tex\w+t";
let actual = find_and_replace(input, commands).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn replace_multiline_text() {
let input = r#"Lorem Ipsum is simply dummy text
of the printing and typesetting industry. Lorem Ipsum
has been the industry's standard dummy text ever since
the 1500s, when an unknown printer took a galley of
type and scrambled it to make a type specimen book.
It has"#;
let commands = &[r"s/\w+/_/g"];
let expected = "_ _ _ _ _ _\n_ _ _ _ _ _. _ _\n_ _ _ _\'_ _ _ _ _ _\n _ _, _ _ _ _ _ _ _ _\n_ _ _ _ _ _ _ _ _ _.\n_ _";
let actual = find_and_replace(input, commands).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn process_multiline_text_multicommand() {
let input = r#"Lorem Ipsum is simply dummy text
of the printing and typesetting industry. Lorem Ipsum
has been the industry's standard dummy text ever since
the 1500s, when an unknown printer took a galley of
type and scrambled it to make a type specimen book.
It has"#;
let commands = &[r"s/[a-z]+/_/g", r"s/[0-9+]/=/g", r"s/_//g", r"s/ +//g"];
let expected = "LI\n.LI\n\'\n====,\n.\nI";
let actual = find_and_replace(input, commands).unwrap();
assert_eq!(expected, actual);
}
}