user2979757
user2979757

Reputation: 821

Regex to insert words into background declaration of a CSS file

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

Answers (3)

Casimir et Hippolyte
Casimir et Hippolyte

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

femtoRgon
femtoRgon

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

max
max

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

Related Questions