PHP preg_replace_callback, замените только 1 обратную ссылку?

Используя preg_replace_callback , можно ли заменить только одну preg_replace_callback ? Или мне нужно вернуть все это?

Я просто пытаюсь поместить значение маркера по умолчанию в кавычки.

 $str = 'This is a {$token|token was empty}'; $str = preg_replace_callback('~{\$\w+\|(.*)?}~i', function($match) { //$match[1] is "token was empty" //I want to just replace $match[1], but it needs me to return the whole thing }, $str); 

Должен ли я захватить больше обратных ссылок, чтобы я смог создать новую версию токена и вернуть его, я не могу просто заменить backreference 1? Благодарю.

Должен ли я захватить больше обратных ссылок, чтобы я смог создать новую версию токена и вернуть его, я не могу просто заменить backreference 1?

У вас есть два варианта:

  1. Используйте дополнительные обратные ссылки для создания строки замены, как вы сказали, или
  2. используйте lookarounds, чтобы соответствовать только той части, которую вы хотите заменить.

Обычно я рекомендую использовать первый подход, так как второй бит менее эффективен и может приводить к недействительным совпадениям в некоторых случаях (когда просматриваемые и скрытые могут перекрываться). В этом случае не было бы проблем.

Пример второго варианта:

 preg_replace_callback('~{\$\w+\|\K(?:[^{}]+)?(?=})~i', function($match){ // $match[0] contains what used to be the first capturing group. // return the value you want to replace it with // (you can still use the capturing group if you want, but it's unnecessary) }); 
  • \K – это способ исключить все из него из фактического соответствия (например, если бы мы имели переменную длину lookbehind там).
  • (?=}) – это взгляд, говорящий, что следующее должно быть a } но не включает его в совпадение.

Вместо этого вы хотите использовать регулярное выражение:

 ~\{\$(\w+?)(?:\|(.+?))?\}~i 

Затем вы можете легко увидеть, что передается вашему обратному вызову:

 $str = 'This is a {$token|token was empty}'; $str = preg_replace_callback('~\{\$(\w+?)(?:\|(.+?))?\}~i', function($match) { var_dump($match); exit; }, $str); 

Вывод:

 array(3) { [0]=> string(24) "{$token|token was empty}" [1]=> string(5) "token" [2]=> string(15) "token was empty" } 

И оттуда вы можете проверить, установлен ли $match[1] , и если да, верните его значение, в противном случае верните $match[2] :

 $foo = 'foo'; $str = 'Foo: {$foo|not set}, Bar: {$bar|not set}'; $str = preg_replace_callback('~\{\$(\w+?)(?:\|(.+?))?\}~i', function($match) { if (isset($GLOBALS[$match[1]])) { return $GLOBALS[$match[1]]; } else { return $match[2]; } }, $str); var_dump($str); 

Вывод:

 string(22) "Foo: foo, Bar: not set" 

Примечание. Я использую $GLOBALS здесь только для демонстрационных целей. Я бы предложил использовать привязку закрытия PHP 5.4, если это вообще возможно, с тех пор вы можете назначить закрытие определенного объекта как контекста (например, ваш объект шаблона / представления или что-то, что содержит переменные, которые вы пытаетесь заменить) , Если вы не используете PHP 5.4, вы также можете использовать function($match) use ($obj) синтаксиса function($match) use ($obj) , где $obj – ваш контекст, а затем проверьте isset($obj->{$match[1]}) внутри вашего закрытия.

Недавно я придумал более простой способ сделать это. Например; если я хочу сопоставить \w+\d+\w+ и только изменить цифры.

 $value = preg_replace_callback('~(\w+)(\d+)(\w+)~', function($match) { $match[2] = $match[2] * 2;//Do whatever I want to $match[2] return $match[1] . $match[2] . $match[3]; }, $value); 

Очень чистый!