preg_replace with multiple patterns replacements at once
Asked Answered
A

2

3

I have few substitutions to apply on my $subject but I don't want to allow the output from old substitutions #(1 .. i-1) to be a match for the current substitution #i.

$subject1 = preg_replace($pat0, $rep0, $subject0);
$subject2 = preg_replace($pat1, $rep1, $subject1);
$subject3 = preg_replace($pat2, $rep2, $subject2);

I tried using one preg_replace with arrays for patterns and replacement hoping that it make it at once; but it turned out to be not more than calling the simple preg_replace successively (with some optimization of course)

After I read about preg_replace_callback, I guess it is not a solution.

Any help?

Addams answered 3/7, 2011 at 20:28 Comment(0)
S
5

Use a callback, you can detect which pattern matched by using capturing groups, like (?:(patternt1)|(pattern2)|(etc), only the matching patterns capturing group(s) will be defined.

The only problem with that is that your current capturing groups would be shifted. To fix (read workaround) that you could use named groups. (A branch reset (?|(foo)|(bar)) would work (if supported in your version), but then you'd have to detect which pattern has matched using some other way.)

Example

function replace_callback($matches){
    if(isset($matches["m1"])){
        return "foo";
    }
    if(isset($matches["m2"])){
        return "bar";
    }
    if(isset($matches["m3"])){
        return "baz";
    }
    return "something is wrong ;)";
}

$re = "/(?|(?:regex1)(?<m1>)|(?:reg(\\s*)ex|2)(?<m2>)|(?:(back refs) work as intended \\1)(?<m3>))/";

$rep_string = preg_replace_callback($re, "replace_callback", $string);

Not tested (don't have PHP here), but something like this could work.

Storage answered 3/7, 2011 at 21:1 Comment(3)
Thank you for the answer. I a have already done it without named groups following the answer of @leonbloy. But if you showed how to employ named groups it would be great.Addams
Thank you for the example. This more simple than what I did.Addams
Actually, I don't like repetitive if statements. I started playing with array_keys() but I have stopped now coz it takes time from me. For the moment, I am satisfied with my solution that uses an extra call to preg_match without repetitive if statementsAddams
I
1

It seems to me that preg_replace_callback is the most direct solution. You just specify the alternate patterns with the | operators and inside the callback you code an if or switch. Seems the right way to me. Why did you discard it?

An alternative solution is to make a temporary replace to a special string. Say:

// first pass
$subject = preg_replace($pat0, 'XXX_MYPATTERN0_ZZZ', $subject);
$subject = preg_replace($pat1, 'XXX_MYPATTERN1_ZZZ', $subject);
$subject = preg_replace($pat2, 'XXX_MYPATTERN2_ZZZ', $subject);
// second pass
$subject = preg_replace("XXX_MYPATTERN0_ZZZ",$rep0 , $subject);
$subject = preg_replace("XXX_MYPATTERN1_ZZZ",$rep1 , $subject);
$subject = preg_replace("XXX_MYPATTERN2_ZZZ",$rep2 , $subject);

This is very ugly, does not adapt well to dynamic replacements, and it's not foolproof, but for some "run once" script it might be acceptable.

Idyllic answered 3/7, 2011 at 20:40 Comment(2)
Thanks very much for your answer. I'll study your first solution now because I like the ideaAddams
Thanks, I did it following your idea but I accepted the answer of @Storage because he gave more explanation and provided a complete exampleAddams

© 2022 - 2024 — McMap. All rights reserved.