Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the idiomatic approach for Replacers that may fail? #648

Closed
Zireael-N opened this issue Feb 23, 2020 · 2 comments
Closed

What's the idiomatic approach for Replacers that may fail? #648

Zireael-N opened this issue Feb 23, 2020 · 2 comments
Labels

Comments

@Zireael-N
Copy link

I've been trying to reimplement the following logic in Rust: Lua, PHP.

Basically, they use a regular expression to unescape some sequences and throw an exception if it's not a known one. I tried to do a similar thing but ran into an issue that Replacer is expected to be a function that returns String, not Result<String, _>.

I circumvented this by panic!()-ing inside my Replacer and wrapping a replace_all() call in std::panic::catch_unwind() but, AFAIK, it's a pretty terrible solution.

Is there a better approach? (Other than not using regular expressions for deserializing, haha)

@BurntSushi
Copy link
Member

It's hard for me to understand the problem you're trying to solve without seeing a complete Rust program. Could you provide a minimal reproducible example of your problem? For example, based on your description, it's not clear to me why the error needs to come at replacement time instead of being checked for before doing a replacement. I just don't understand enough about what you're trying to do.

In the general case though, this is probably your best bet: https://stackoverflow.com/questions/60068408/how-do-i-bubble-up-an-error-from-the-closure-passed-to-regexregexreplace

Which isn't ideal, especially since there is no way to stop the replacement routine. At this point, I'd recommend not using regex's replacement functionality at all. It's really provided as a convenience. Implementing replacements on top of captures_iter is fairly simple to do, so I'd recommend just doing that:

fn replace_all(
    re: &Regex,
    haystack: &str,
    replacement: impl Fn(&Captures) -> Result<String, Error>,
) -> Result<String, Error> {
    let mut new = String::with_capacity(haystack.len());
    let mut last_match = 0;
    for caps in re.captures_iter(haystack) {
        let m = caps.get(0).unwrap();
        new.push_str(&haystack[last_match..m.start()]);
        new.push_str(&replacement(&caps)?);
        last_match = m.end();
    }
    new.push_str(&haystack[last_match..]);
    Ok(new)
}

Full playground example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=196fc0d1301cb257af2bf906d869a4af

@Zireael-N
Copy link
Author

This implementation of replace_all is exactly what I needed, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants