Wonko the Sane
Wonko the Sane

Reputation: 832

Conditional search and replace using PHP and regex

I need to hide all "p" tags in a HTML file that have an inline style with a "left" offset of 400 or more.

I'm hoping some clever regex will replace "left:XXX" with "display:none" should "xxx" be 400 or more.

For example, this:

<p style="position:absolute;top:98px;left:472px;white-space:nowrap">

...would need to be replaced with this:

<p style="position:absolute;top:98px;display:none;white-space:nowrap">

It seems simple enough logic, but the regex and PHP is mind boggling for me.

Here is what I've been trying to do, but I can only get it to work line-by-line:

$width = preg_match("left:(.*?)px",$contents);
if ($width >399)
{
    $contents = preg_replace('/left:(.*?)px/', "display:none", $contents);
}

Any suggestions greatly appreciated! :)

Wonko

Upvotes: 1

Views: 80

Answers (2)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89547

Don't believe that regex will solve all the problem of the world:

Use DOMDocument to extract the p tags with a style attribute, extract the "left" value with a regex pattern from the style attribute and then proceed to the replacement when the "left" value is greater or equal to 400 (test this with a simple comparison).

$dom = new DOMDocument;
$dom->loadHTML($html);

$pTags = $dom->getElementsByTagName('p');

foreach($pTags as $pTag) {
    if ($pTag->hasAttribute('style')) {
        $style = $pTag->getAttribute('style');
        $style = preg_replace_callback(
            '~(?<=[\s;]|^)left\s*:\s*(\d+)\s*px\s*(?:;|$)~i',
            function ($m) {
                return ($m[1] > 399) ? 'display:none;' : $m[0];
            },
            $style
        );
        $pTag->setAttribute('style', $style);
    }
}

$result = $dom->saveHTML();

EDIT: in the worst scenario, the style attribute may contain display:block; or display with a value other than none after the left value. To avoid any problem, it is better to put display:none at the end.

$style = preg_replace_callback(
    '~(?<=[\s;]|^)left\s*:\s*(\d+)\s*px\s*(;.*|$)~i',
    function ($m) {
        return ($m[1] > 399) ? $m[2]. 'display:none;' : $m[0];
    },
    $style
);

Upvotes: 2

user4795756
user4795756

Reputation:

I've tested it and it works correctly:

$string = '<p style="position:absolute;top:98px;left:472px;white-space:nowrap">';

 $test = str_replace('left:', 'display:none;[', $string );
 $test = str_replace('white-space', ']white-space', $test );
 $out = delete_all_between('[', ']', $test);
 print($out); // output

function delete_all_between($beginning, $end, $string) {
  $beginningPos = strpos($string, $beginning);
  $endPos = strpos($string, $end);
  if ($beginningPos === false || $endPos === false) {
    return $string;
  }

  $textToDelete = substr($string, $beginningPos, ($endPos + strlen($end)) - $beginningPos);

  return str_replace($textToDelete, '', $string);
}

output:

<p style="position:absolute;top:98px;display:none;white-space:nowrap">

enjoy it ... !

Upvotes: 1

Related Questions