Reputation: 821
I want to parse a CSS file and every time there is background:[some properties] (12px) (10px) [some properties];
changes to `background:[some properties] right (12px) top (10px) [some properties];
I have tried this regex:
(background\s*:.*?)\s(\d+([a-z]+|%|))\s+(\d+([a-z]+|%|));
but it catches:
background:url(../images/header.jpg) top no-repeat; height:123px; float:left; padding:65px left 0px top 0px 120px;
You can see in this fiddle, the only string it should catch is this:
background:url(../images/header.jpg) 10px 0 no-repeat;
but it catches an extra string.
How do I stop the regex pattern after ;
, so it will not continue to the next css rule? and what is the right pattern here?
Upvotes: 1
Views: 94
Reputation: 89547
You can try this:
$result = preg_replace('/\bbackground\s*:[^;]*?\K(\d+(?:px|e[mx]|%)?+\s+)(\d+(?:px|e[mx]|%)?+)/i', 'right $1 top $2', $string);
example:
<?php
$string = <<<'LOD'
#banner{width:814px; background:url(../images/header.jpg) top no-repeat; height:123px; float:left; padding:65px 0px 0px 120px; font-family: Georgia, "Times New Roman", Times, serif; font-size:30px; color:#fff;}
#banner2{width:814px; background:url(../images/header.jpg) 10px 0 no-repeat; height:123px; float:left; padding:65px 0px 0px 120px; font-family: Georgia, "Times New Roman", Times, serif; font-size:30px; color:#fff;}
#banner3{width:814px; background:url(../images/header.jpg) left 10px top 0 no-repeat; height:123px; float:left; padding:65px 0px 0px 120px; font-family: Georgia, "Times New Roman", Times, serif; font-size:30px; color:#fff;}
LOD;
$result = preg_replace('/\bbackground\s*:[^;]*?\K(\d+(?:px|e[mx]|%)?+)\s+(\d+(?:px|e[mx]|%)?+)/i', 'right $1 top $2', $string);
print_r($result);
pattern details:
(?:....)
is a non capturing group
\K
resets all the match from match result before it
\b
is a word boundary. It's a zero-width assertion, a border between a member of the \w
character class and another character
[^;]
is a negative character class that means "all character except ;
"
a quantifier is by default greedy (it catch all that is possible), if you want it catch the less possible (lazy), you must add a question mark after (*?
, +?
, ??
, {1,5}?
)
Upvotes: 2
Reputation: 33341
This should work:
(background\s*:[^;]*?)\s(\d+([a-z]+|%|))\s+(\d+([a-z]+|%|)).*?;
I've replace your first .*
with [^;]*
, or anything except a semi-colon. This will prevent the regex traversing past the first semicolon before matching the numeric values you are looking for.
I've also added a .*?
before the final semi-colon, to allow it to traverse past any extra data after the two numeric values, such as "no-repeat" in your example. That .*?
could be replaced with [^;]*
, if you prefer.
Upvotes: 0
Reputation: 2817
Your regex expects that background
property will end with two numbers and ;
and does not expect to meet no-repeat
there. Try this regex
(background\s*:.*?)\s(\d+([a-z]+|%|))\s+(\d+([a-z]+|%|)).*?;
Upvotes: 0