preg_replace с несколькими заменами шаблонов одновременно - PullRequest
3 голосов
/ 04 июля 2011

У меня есть несколько подстановок для моего $ subject, но я не хочу, чтобы выходные данные старых подстановок # (1 .. i-1) соответствовали текущей подстановке # i.

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

Я пытался использовать один preg_replace с массивами для шаблонов и замены, надеясь, что он сделает это сразу; но оказалось, что это не более чем последовательный простой вызов preg_replace (с некоторой оптимизацией, конечно)

После того, как я прочитал о preg_replace_callback , я думаю, что это не решение.

Любая помощь?

Ответы [ 2 ]

3 голосов
/ 04 июля 2011

Воспользовавшись обратным вызовом, вы можете определить, какой шаблон соответствует, используя группы захвата, например (?:(patternt1)|(pattern2)|(etc), будут определены только соответствующие группы захвата шаблонов.

Единственная проблема в том, что ваши текущие группы захвата будут сдвинуты. Чтобы исправить (прочитайте обходной путь), что вы могли бы использовать именованные группы. (Сброс ветви (?|(foo)|(bar)) будет работать (если поддерживается в вашей версии), но тогда вам нужно будет определить, какой шаблон соответствует, другим способом.)

Пример

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);

Не проверено (здесь нет PHP), но что-то подобное может работать.

1 голос
/ 04 июля 2011

Мне кажется, что preg_replace_callback - самое прямое решение.Вы просто указываете альтернативные шаблоны с помощью операторов |, а внутри обратного вызова вы кодируете if или switch.Кажется, правильный путь для меня.Почему вы его выбросили?

Альтернативное решение - сделать временную замену специальной строке.Скажем:

// 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);

Это очень уродливо, плохо адаптируется к динамическим заменам и не защищено от ошибок, но для некоторых сценариев "выполнить один раз" это может быть приемлемо.

...