8

I'm porting a pluralizer to Rust and I'm having some difficulty with regular expressions. I can't get the Regex::replace() method to replace a numbered capture group as I would expect. For example, the following displays an empty string:

let re = Regex::new("(m|l)ouse").unwrap();
println!("{}", re.replace("mouse", "$1ice"));

I would expect it to print "mice", as it does in JavaScript (or Swift, Python, C# or Go)

var re = RegExp("(m|l)ouse")
console.log("mouse".replace(re, "$1ice"))

Is there some method I should be using instead of Regex::replace()?

Examining the Inflector crate, I see that it extracts the first capture group and then appends the suffix to the captured text:

if let Some(c) = rule.captures(&non_plural_string) {
    if let Some(c) = c.get(1) {
        return format!("{}{}", c.as_str(), replace);
    }
}

However, given that replace works in every other language I've used regular expressions in, I would expect it work in Rust as well.

Andy S
  • 8,641
  • 6
  • 36
  • 40

1 Answers1

10

As mentioned in the documentation:

The longest possible name is used. e.g., $1a looks up the capture group named 1a and not the capture group at index 1. To exert more precise control over the name, use braces, e.g., ${1}a.

And

Sometimes the replacement string requires use of curly braces to delineate a capture group replacement and surrounding literal text. For example, if we wanted to join two words together with an underscore:

let re = Regex::new(r"(?P<first>\w+)\s+(?P<second>\w+)").unwrap();
let result = re.replace("deep fried", "${first}_$second");
assert_eq!(result, "deep_fried");

Without the curly braces, the capture group name first_ would be used, and since it doesn't exist, it would be replaced with the empty string.

You want re.replace("mouse", "${1}ice")

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I can't believe I missed that. I must've read that section 20 times. That works perfectly! Thank you! – Andy S Jun 02 '17 at 16:01