1

I want to be able to replace phrases like "you are" to " I am" and "your" to "my". How would I do this while keeping my code DRY?

so far I have something like this...

let re = Regex::new(r"you are").unwrap();
re.replace_all("you are awesome and so is your hat", "I am")

But this only replaces the "you are" but not the "my" part.

I think ideally it'll look something like

let re = Regex::new(r"your|you are").unwrap();
re.replace_all("you are awesome and so is your hat", fn_with_pattern_matching)
Vin
  • 885
  • 1
  • 6
  • 7
  • how about writing 2 individual replace_all statements? – karthik manchala Jan 05 '16 at 13:37
  • Your last snippet with `fn_with_pattern_matching` should be workable. See the example in the `regex` docs: http://doc.rust-lang.org/regex/regex/enum.Regex.html#examples-2 You will likely need to make use of capture groups to determine which text to use as a replacement though. – BurntSushi5 Jan 05 '16 at 14:05
  • @BurntSushi5, yeah I've tried using capture groups but I have alotta trouble understanding the docs and can't seem to get it working as intended – Vin Jan 05 '16 at 14:14
  • @BurntSushi5 I think that method also requires me to explicitly identify capture index numbers, which is not desirable if I don't know whether the string has those phrases – Vin Jan 05 '16 at 14:24
  • 1
    Please [edit] your question to show what you have tried. Stack Overflow isn't a service where other people write code for you. Show us what you have written to implement `fn_with_pattern_matching` and we can help get that to work. – Shepmaster Jan 05 '16 at 14:45

2 Answers2

2

You can do the following:

let str = "you are awesome and so is your hat";
let re = Regex::new(r"you are").unwrap();
let re1 = Regex::new(r"your").unwrap();
re.replace_all(str, "I am");
re1.replace_all(str, "my");

Edit:

If you have lot of phrases to replace, create a map of ("phrase to replace", "phrase to replace with") and iterate over it to perform the above logic.

karthik manchala
  • 13,492
  • 1
  • 31
  • 55
  • Thanks for the suggestion but this is not very DRY and doesn't scale well at all. I'm planning on adding a lot more phrases to replace (eg. "I" to "you"...etc) – Vin Jan 05 '16 at 14:12
  • 2
    *but this is not very DRY* — place all the strings in an array and iterate over the array. If your application logic is "replace all A with B, then all C with D, then all E with F", then the code will reflect that repeated logic. – Shepmaster Jan 05 '16 at 14:44
2

Let us start with karthik manchala answer and Shepmaster suggestion:

place all the strings in an array and iterate over the array. If your application logic is "replace all A with B, then all C with D, then all E with F", then the code will reflect that repeated logic.

Instead of keeping the strings in an array I would recommend storing the compiled regular expressions there in order not to rebuild them every time.

Here's the code:

extern crate regex;

use regex::Regex;
use std::env::args;
use std::iter::FromIterator;

fn main() {
    let patterns = [("your", "mine"), ("you are", "I am")];
    let patterns = Vec::from_iter(patterns.into_iter().map(|&(k, v)| {
        (Regex::new(k).expect(&format!("Can't compile the regular expression: {}", k)),
         v)
    }));
    for arg in args().skip(1) {
        println!("Argument: {}", arg);
        for &(ref re, replacement) in patterns.iter() {
            let got = re.replace_all(&arg, replacement);
            if got != arg {
                println!("Changed to: {}", got);
                continue;
            }
        }
    }
}

That would be it, but for the sake of completeness I'd like to add that if you want superior performance then you might use the MARK feature present in the PCRE regular expressions engine (pcre crate).

With MARK and a patterns like this

"(?x) ^ (?:
    (*MARK:0) first pattern \
  | (*MARK:1) second pattern \
  | (*MARK:2) third pattern \
)"

you can use the MARK number for classification or in your case as an index into an array with replacements. This is often better than using multiple regular expressions because the subject string is only processed once.

ArtemGr
  • 11,684
  • 3
  • 52
  • 85
  • *"because the subject string is only processed once"* — which also changes the behavior, correct? For example, if I replace `A -> BC` and `B -> XY`, then making multiple loops vs a single loop with multiple matches will yield different results. – Shepmaster Jan 06 '16 at 14:25
  • 1
    @Shepmaster That depends on how the loop was implemented in the first place and what the regular expressions are. There are cases where the behaviour would be the same and the only difference will be in the runtime cost. As usual, the developer should understand what she's doing. My goal here was not to write a book about regular expressions, `MARK`, and all the nuances thereof, but to simply mention that valuable tool. ; ) – ArtemGr Jan 06 '16 at 14:30