A closure that I pass to regex::Regex::replace_all
may fail. I don't want it to panic in that case but retrieve the error. I tried 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| {
let n_result: Result<i32, _> = caps[0].parse();
match n_result {
Ok(n) => (n * 2).to_string(),
Err(err) => {
error = Some(format!("invalid number encountered: {err}").into());
String::new() // dummy
}
}
});
if let Some(err) = error {
Err(err)?;
}
Ok(())
}
Errors:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.94s
Running `target/debug/playground`
Error: "invalid number encountered: number too large to fit in target type"
That works but it's somewhat ugly. It also will not short-circuit on error.
Implementing Replacer
myself, which is a possible solution in this case, doesn't seem to work either, because Replacer::replace_append
isn't fallible.
Does that mean I would have to implement the code of Regex::replacen
on my own or live with the solution above (that involves a temporary variable and inserting empty dummy strings)?
P.S.: My real-world use case uses floats, so I guess it's okay for me to just parse them as f64::NAN
(example in Playground), but I'm still interested in how this problem would be solved in general. Maybe it's a corner case that doesn't occur often.
P.P.S.: Just encountered another case where I can't use f64::NAN
as a workaround.
The second real-world use case looks like this:
fn render<'a>(&self, machine: &LuaMachine<'a>) -> anyhow::Result<String> {
let output = RE_CODE.replace_all(&self.template, |caps: &Captures| {
if let Some(assign) = caps.name("assign") {
let (line, col) = line_column(&self.template, assign.start());
let name = format!("assignment in line #{line}, column #{col}");
let func = machine
.compile(Some(name), assign.as_str())
.context("could not compile Lua assignment")?;
func.call([])
.context("runtime error when executing Lua assignment")?;
String::new()
} else if let Some(expr) = caps.name("expr") {
let (line, mut col) = line_column(&self.template, expr.start());
col -= 1;
let name = format!("expression in line #{line}, column #{col}");
let func = machine
.compile(Some(name), format!("return tostring({})", expr.as_str()))
.context("could not compile Lua expression")?;
func.call_1ret([])
.context("runtime error when executing Lua expression")?
.try_into_string()
.context("Lua did not return a string")?
} else {
unreachable!()
}
});
let output = RE_COMMENT.replace_all(&output, "");
Ok(output.to_string())
}
And I obviously can't use the ?
operator within the closure passed to replace_all
.