Reputation: 23
In php
I want to replace the $
in {{ $here $their '$literal' }}
with $this->
.
Which means I would like the result {{ $this->here $this->their '$literal' }}
, but what I get instead is: {{ $this->here $their '$literal' }}
this is my code:
<?php
$str = '{{ $here $their "$literal" }}';
$search = '{{(?:\'[^\']+\'|"[^"]+")(*SKIP)(*F)|\$([0-9a-zA-Z_]++)}}';
$replace = '$this->$1';
// result is {{ $hello $this->by "$literal" }}
$result = preg_replace('/' . $search . '/U', $replace, $str);
?>
Does anyone know how to replace multiple occurrences within the {{ }} that are not quoted?
Upvotes: 2
Views: 88
Reputation: 89557
If your string is already enclosed between double curly brackets, you only have to write this:
$pattern = '~[^"\'$]*+(?:"[^"]*"[^"\'$]*|\'[^\']*\'[^"\'$]*)*+\$\b\K~A';
$str = preg_replace($pattern, 'this->', $str);
But if your double curly brackets enclosed part is in a larger text and you don't want to replace other $var
outside curly brackets, you need this one:
$pattern = '~(?:\G(?!\A)|{{)[^"\'$}]*+(?:"[^"]*"[^"\'$}]*|\'[^\']*\'[^"\'$}]*)*+\$\b\K~';
with the same replacement string.
Pattern 1 details:
This pattern matches all characters until a $ (included). The easiest way to avoid quoted parts is to match all of them before a dollar and to remove all from the match result using \K
.
The A modifier (similar of \G
at the start of the pattern) ensures that all matches are contiguous (without gaps).
~ # pattern delimiter
[^"'$]*+ #"# all characters except quotes and dollars
(?: # quoted parts
"[^"]*" [^'"$]*
|
'[^']*' [^"'$]*
)*+
\$
\b # no need to write `[a-zA-Z0-9_]+` and to capture it
# after a literal "$" a word boundary suffices.
\K # KEEP: characters before this token are removed from the match result
~A # ANCHORED: force the matches to be contiguous from the start
# of the string until the last match. If one position fails, no
# more match are possible
Upvotes: 1
Reputation: 98901
You probably need something like:
$str = '{{ $here $their "$literal" }}';
$result = preg_replace('/(\$.*?)\s(\$.*?)/i', '$this->$1 $this->$2', $str);
Upvotes: 0
Reputation: 626748
Match the {{...}}
substrings within preg_replace_callback
and then use your preg_replace
inside the anonynous method with a bit adjusted regex:
$str = '{{ $here $their "$literal" }}';
echo preg_replace_callback('~{{.*?}}~s', function($m) {
return preg_replace('~(?:\'[^\']+\'|"[^"]+")(*SKIP)(*F)|\$\b~', '$this->$0', $m[0]);
}, $str);
See the PHP demo
The '~{{.*?}}~s'
regex will match non-overlapping occurrences of {{
, any 0+ chars as few as possible up to the first }}
. The regex inside the preg_replace
is a bit more complex:
(?:\'[^\']+\'|"[^"]+")(*SKIP)(*F)
- '
followed with 1+ chars other than '
and then '
(due to \'[^\']+\'
), or "
followed with 1+ chars other than "
and then "
(due to "[^"]+"
), and once that substring is matched, it is discarded and the regex engine proceeds to the next match (due to (*SKIP)(*F)
)|
- or\$\b
- a $
symbol that is followed with a word character.Upvotes: 1