Fallible replace_all for regular expressions

A (sort of) short-circuiting variant would be this:

use regex::{Captures, Regex};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let re = Regex::new("[0-9]+").unwrap();
    let s = "123, 12345678901234567890";
    let mut error: Option<Box<dyn std::error::Error>> = None;
    let _s2 = re.replace_all(s, |caps: &Captures| {
        if error.is_some() {
            return String::new(); // dummy
        }
        match (|| {
            let n: i32 = caps[0].parse()?;
            Ok::<_, Box<dyn std::error::Error>>((n * 2).to_string())
        })() {
            Ok(x) => x,
            Err(err) => {
                error = Some(err);
                String::new() // dummy
            }
        }
    });
    if let Some(err) = error {
        Err(err)?;
    }
    Ok(())
}

(Playground)

But… it feels even more ugly than my first attempt. :slightly_frowning_face:


Or maybe do two runs?

use regex::{Captures, Regex};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let re = Regex::new("[0-9]+").unwrap();
    let s = "123, 12345678901234567890";
    let mut replacements: Vec<String> = Vec::new();
    for caps in re.captures_iter(s) {
        let n: i32 = caps[0].parse()?;
        replacements.push((n * 2).to_string());
    }
    let mut replacements_iter = replacements.into_iter();
    let _s2 = re.replace_all(s, |_: &Captures| {
        replacements_iter.next().unwrap()
    });
    Ok(())
}

(Playground)