Currently I am separating css rules by using
preg_match_all( '/(?ims)([a-z0-9s,.:()#_\-@>*]+){([^}]*)}/', $content, $arr);
It's working fine. However, if I have double curly brackets like this
@keyframes animationName1{0%{opacity: 0}100%{opacity:1}}div{opacity:0}@keyframes animationName2{0%{opacity: 0}100%{opacity:1}}
this regex will not extract all of the animation rules due to the curly brackets within. I need suport in adapting said rule to look at the outer brackets and ignore the inner ones.
These should be the results:
1: @keyframes animationName1{0%{opacity: 0}100%{opacity:1}}
2: div{opacity:0}
3: @keyframes animationName2{0%{opacity: 0}100%{opacity:1}}
You can use
([^{}]+)({((?:[^{}]++|(\g<2>))*)})
See the regex demo. Details:
([^{}]+) - Capturing group 1: one or more chars other than { and }({((?:[^{}]++|(\g<2>))*)}) - Group 2:
{ - a { char((?:[^{}]++|(\g<2>))*) - Group 3: zero or more occurrences of any one or more chars other than { and } or Group 2 pattern (recursed)} - a } charSee the PHP demo:
$text = "@keyframes animationName1{0%{opacity: 0}100%{opacity:1}}div{opacity:0}@keyframes animationName2{0%{opacity: 0}100%{opacity:1}}";
$rx = '~([^{}]+)({(?:[^{}]++|(\g<2>))*})~';
if (preg_match_all($rx, $text, $m)) {
print_r($m[0]);
}
Output:
Array
(
[0] => @keyframes animationName1{0%{opacity: 0}100%{opacity:1}}
[1] => div{opacity:0}
[2] => @keyframes animationName2{0%{opacity: 0}100%{opacity:1}}
)
If the format is always the same, you can also either match from 2 opening curly's till 2 closing curly's starting with an @ or match word chars followed by a single opening till closing curly.
(?s)@\w+\h+\w+\s*{[^{]*{.*?}\s*}|\w+{[^{}]+}
(?s) Inline modifier, make the dot match a newline (if on multiple lines)@\w+\h+\w+\s* Match @ and 1+ word chars, spaces and again word chars{[^{]*{ Match { then optional chars other than { and again {.*? Match as least as possible chars}\s*} Match }} with optional whitespace chars in between| Or\w+{[^{}]+} Match word chars and from {...}$re = '/(?s)@\w+\h+\w+\s*{[^{]*{.*?}\s*}|\w+{[^{}]+}/';
$str = '@keyframes animationName1{0%{opacity: 0}100%{opacity:1}}div{opacity:0}@keyframes animationName2{0%{opacity: 0}100%{opacity:1}}';
preg_match_all($re, $str, $matches);
print_r($matches[0]);
Output
Array
(
[0] => @keyframes animationName1{0%{opacity: 0}100%{opacity:1}}
[1] => div{opacity:0}
[2] => @keyframes animationName2{0%{opacity: 0}100%{opacity:1}}
)