I'm trying to replace all "
" in twig syntax when it's surrounded by "{%
" and "%}
" or "{{
" and "}}
".
For example in the following string :
<p>{{ myFunction() }}</p>
<p> </p>
<p>{{ number|number_format(2, " . ", ' , ') }}</p>
<p>{% set myVariable = ' ' %}</p>
I want to replace every "
" by "" except the "
<p> </p>
" one.
I'm doing the following :
$content = preg_replace('/({[{%].*)( )(.*[}%]})/', '$1 $3', $content);
but it replace only one occurrence of " 
" in each brackets surroundings.
How to make it for all?
I'm trying to replace all
in twig syntax when it's surrounded by{%
and%}
or{{
and}}
.
If you are seeking for the easiest solution, just match all substrings that start with {{
and end with }}
, or that start with {%
and end with %}
with '~{{.*?}}|{%.*?%}~s'
regex, and use the pattern with the preg_replace_callback
where you can further manipulate the match value inside the anonymous function:
preg_replace_callback('~{{.*?}}|{%.*?%}~s', function ($m) {
return str_replace(' ', '', $m[0]);
}, $s);
See the PHP demo
Pattern details:
{{.*?}}
- match {{
, then any 0+ characters as few as possible (due to the lazy *?
quantifier) up to the closest }}
|
- or{%.*?%}
- match {%
, then any 0+ characters as few as possible up to the closest %}
~s' - enables the DOTALL modifier so that
.` could also match newline symbols.\G
is your friend here:
(?:(?:\{{2}|\{%) # the start
|
\G(?!\A)) # or the beginning of the prev match
(?:(?!(?:\}{2}|%\})).)*?\K # do not overrun the closing parentheses
# match a
PHP
:<?php
$string = <<<DATA
<p>{{ myFunction() }}</p>
<p> </p>
<p>{{ number|number_format(2, " . ", ' , ') }}</p>
<p>{% set myVariable = ' ' %}</p>
DATA;
$regex = '~
(?:(?:\{{2}|\{%)
|
\G(?!\A))
(?:(?!(?:\}{2}|%\})).)*?\K
~x';
$string = preg_replace($regex, ' ', $string);
?>
A full code example can be found on ideone.com.
Regex:
(?=(?:(?!{[{%]).)*[%}]})
Explanation:
# Match non-breaking spaces (HTML entity)
(?= # Start of positive lookahead
(?: # Start of non-capturing group (a)
(?!{[{%]) # Asserts that next 2 characters are not {{ or {% (negative lookahead)
.)* # Match any other characters (greedy) (except new-lines) (end of (a))
[%}]} # Up to a }} or %}
) # End of positive lookahead
In simple words it means all
s that are finally followed by %}
or }}
and asserts they are within a {{...}} or {%...%} block.
If you have ending delimiters not in the same line like below:
<p>{{ myFunction()
}}</p>
<p> </p>
<p>{{ number|number_format(2, " . ", ' , ')
}}</p>
<p>{% set myVariable = ' '
%}</p>
Then you will need s
modifier on by appending (?s)
to regex:
(?s) (?=(?:(?!{[{%]).)*[%}]})
You may use it by default as well.
PHP:
preg_replace('/ (?=(?:(?!{[{%]).)*[%}]})/', ' ', $input);