Home » Php » php – preg_replace out CSS comments?

php – preg_replace out CSS comments?

Posted by: admin July 12, 2020 Leave a comment

Questions:

I’m writing a quick preg_replace to strip comments from CSS. CSS comments usually have this syntax:

/* Development Classes*/
/* Un-comment me for easy testing
  (will make it simpler to see errors) */

So I’m trying to kill everything between /* and */, like so:

$pattern = "#/\*[^(\*/)]*\*/#";
$replace = "";
$v = preg_replace($pattern, $replace, $v);

No dice! It seems to be choking on the forward slashes, because I can get it to remove the text of comments if I take the /s out of the pattern. I tried some simpler patterns to see if I could just lose the slashes, but they return the original string unchanged:

$pattern = "#/#";
$pattern = "/\//";

Any ideas on why I can’t seem to match those slashes? Thanks!

How to&Answers:

Here’s a solution:

$regex = array(
"`^([\t\s]+)`ism"=>'',
"`^\/\*(.+?)\*\/`ism"=>"",
"`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
"`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
"`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
);
$buffer = preg_replace(array_keys($regex),$regex,$buffer);

Taken from the Script/Stylesheet Pre-Processor in Samstyle PHP Framework

See: http://code.google.com/p/samstyle-php-framework/source/browse/trunk/sp.php

csstest.php:

<?php

$buffer = file_get_contents('test.css');

$regex = array(
"`^([\t\s]+)`ism"=>'',
"`^\/\*(.+?)\*\/`ism"=>"",
"`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
"`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
"`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
);
$buffer = preg_replace(array_keys($regex),$regex,$buffer);
echo $buffer;

?>

test.css:

/* testing to remove this */
.test{}

Output of csstest.php:

.test{}

Answer:

I don’t believe you can use grouping within a negated character class like you have there. What you’re going to want to use is called Assertions, of which there are two types. “look-ahead” and “look-behind”.

The pattern you’re looking for in English is basically, “forward slash, literal wildcard, anything that isn’t followed by a forward slash or anything other than a literal wildcard that is followed by a forward slash or a forward slash that isn’t preceded by a literal wildcard zero or more times, literal wild card, forward slash

<?php

$str = '/* one */ onemore
/*
* a
* b
**/
stuff // single line
/**/';

preg_match_all('#/\*(?:.(?!/)|[^\*](?=/)|(?<!\*)/)*\*/#s', $str, $matches);
print_r($matches);

?>

Answer:

I had the same issue.
To solve it, I first simplified the code by replacing “/ASTERIX” and “ASTERIX/” with different identifiers and then used those as the start and end markers.

$code = str_replace("/*","_COMSTART",$code);
$code = str_replace("*/","COMEND_",$code);
$code = preg_replace("/_COMSTART.*?COMEND_/s","",$code);

The /s flag tells the search to go onto new lines

Answer:

Just for fun(and small project of course) I made a non-regexp version of a such code (I hope it’s faster):

function removeCommentFromCss( $textContent )
{
    $clearText = "";
    $charsInCss = strlen( $textContent );
    $searchForStart = true;
    for( $index = 0; $index < $charsInCss; $index++ )
    {
        if ( $searchForStart )
        {
            if ( $textContent[ $index ] == "/" && (( $index + 1 ) < $charsInCss ) && $textContent[ $index + 1 ] == "*" )
            {
                $searchForStart = false;
                continue;
            }
            else
            {
                $clearText .= $textContent[ $index ];
            }
        }
        else
        {
            if ( $textContent[ $index ] == "*" && (( $index + 1 ) < $charsInCss ) && $textContent[ $index + 1 ] == "/" )
            {
                $searchForStart = true;
                $index++;
                continue;
            }
        }
    }
    return $clearText;
}