0

I have html eg below and would like to use regular expressions to change the font-size on the fly.

<p><span style="font-size: small;"><img style="float: left;padding:5px" title="Ikechukwu to host Lagos Smirnoff party" src="afrostarpics/586.jpg" alt="Ikechukwu to host Lagos Smirnoff party" width="200" height="300">Smirnoff held a party like never seen before in East, North and West Africa on Friday 23rd September 2011, when they held a “Kick off” party for the Smirnoff Midnight Cruise.&nbsp; The grand party held in the populous West African nation of Nigeria was so successful that it left revellers literally begging for more.</span></p>

this is the regular expression i have

    <?php 
$bd=$nobj->body;//html string to change
$selector="font-size"; //selector to change
$property="1.2em"; //new value
 preg_replace('/('.$selector.'\s*\{[\w\s:\-;\(\)#]*)('.$property.'\s*:)([^;\}]+)(;|\})/Ui', '$1 $4', $bd); 
echo $bd;
?>

any ideas as to why this is not working

Sir Lojik
  • 1,409
  • 7
  • 24
  • 45

3 Answers3

4

If you're set on using regex for this, you'll probably find this pattern more effective:

$bd = preg_replace('/\b'.$selector.'\s*:[^;}"\']*/i', $selector.':'.$property, $bd);

That should do what you're trying to do at least 99% of the time.

However, I want to point out that you seem to be trying to use regex to parse CSS embedded inside HTML, which is not usually something regex is good at. Even with this simple task, to solve it in a robust way you would have to distinguish between HTML attribute values and other text, which means you would have to (at least partially) parse the HTML. Doing that with regex is usually a Bad Idea, but it's incredibly simple for jQuery (client-side) or HTML Purifier (server-side).

Why is regex such a dangerous tool for this? Well, although the task itself is fairly simple, you probably don't know in advance what the plain-text part is going to say, and regex can't tell the difference between plain text and HTML. So if the phrase "font-size:" appears in your plain text (meaning the Smirnoff held a party like... part), it will probably break any sane regex. Unlikely? Yes, but it's still a potential bug.

Community
  • 1
  • 1
Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • 2
    +1 for the mention of the real problem with using RegExp, and why I suggested parsing it as XML (or HTML) and then modifying the attribute. It's not as likely with `font-size`, but how about `He responded with his favorite color: orange, although, he admits, he doesn't really 'get why he...` In that case, my regex, for example, would replace everything from `color` to `'get` with whatever you specified as the new color. No way to avoid it, really, with regex, so semantically parsing the document and modifying the attributes is better. Using a stylesheet or js is even better than that. – Dereleased Oct 13 '11 at 20:54
  • i know j could easily use jquery to solve this but i need to use regex for quick job – Sir Lojik Oct 13 '11 at 22:13
  • i have a result of

    when i run the test function. i want small replaced by 1.2em

    – Sir Lojik Oct 13 '11 at 22:50
  • @SirLojik - Update: Try the current version. I didn't notice the `U` flag in there, and it was causing incorrect behavior. [Without the `U`, it should work fine.](http://rubular.com/r/XKWhj2ajYv) – Justin Morgan - On strike Oct 14 '11 at 14:54
1

One possible reason is that preg_replace returns the modified string, so you have to save and use the return value - something like this will work if the regex is correct:

$bd = preg_replace('/('.$selector.'\s*\{[\w\s:\-;\(\)#]*)('.$property.'\s*:)([^;\}]+)(;|\})/Ui', '$1 $4', $bd);
echo $bd;
Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
akhilless
  • 3,169
  • 19
  • 24
0

Your regular expression looks overly complicated to me.

You could always parse the results as XML, and then modify the attributes, but assuming you still want REGEX, I think something like this should suffice:

$old = '<p><span style="font-weight:bold;color:blue;font-size: small;"><img style="float: left;padding:5px" title="Ikechukwu to host Lagos Smirnoff party" src="afrostarpics/586.jpg" alt="Ikechukwu to host Lagos Smirnoff party" width="200" height="300">Smirnoff held a party like never seen before in East, North and West Africa on Friday 23rd September 2011, when they held a “Kick off” party for the Smirnoff Midnight Cruise.&nbsp; The grand party held in the populous West African nation of Nigeria was so successful that it left revellers literally begging for more.</span></p>';
$selector      = 'font-size';
$desired_value = '1\.2em';
$new = preg_replace(
    '/\b(' . $selector . ')\s*:\s*(?!' . $desired_value . ').+\s*([;"\'])/Ui',
    '\1:' . stripslashes($desired_value) . '\2',
    $old
);

For reference, with the values you gave, that gives an output regex of:

\b(font-size)\s*:\s*(?!1\.2em).+?\s*([;"'])
Dereleased
  • 9,939
  • 3
  • 35
  • 51
  • Honestly, you could probably remove the negative look-ahead assertion, since it won't hurt to replace a value that is already what you want it to be. Probably could stand to add some more spacing, so I'll do that. EDIT: Spacing added after colon and after value of property. That should make it a bit more flexible for weirdly formatted CSS. – Dereleased Oct 13 '11 at 19:55
  • it cuts some stuff eg with your example ... i get

    only output

    – Sir Lojik Oct 13 '11 at 20:14
  • I fixed that problem, sorry; I thought the 'U' modifier was 'unicode' not 'ungreedy', so I was actually making the '+' greedy again. – Dereleased Oct 13 '11 at 20:25