views:

267

answers:

2

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!

+3  A: 

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{}
thephpdeveloper
That took out some spaces and linebreaks, but seemed to leave all comments intact. It definitely looks like the third line SHOULD be removing comments, though. Baffling.
Doug Avery
hi there, it works fine for me - totally. comments were all removed.
thephpdeveloper
Interesting! Thanks for the updated test. I'm running this inside an ExpressionEngine plugin, so I wonder if some environment difference is causing my issues.
Doug Avery
+1  A: 

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);

?>
joebert
Thanks for the in-depth explanation. I can't get this to work in the file I'm using it in, but it works perfectly when isolated, so I suspect I have more problems to figure out...
Doug Avery