Why is this breaking my regex?

Hi all,
Im using a regex to clean up a CSS script.

If I use the following:

 $stylesheet = preg_replace('/#classname \{(.*?)\}/si', '', $stylesheet);

it works fine.

However, when I try this it replaces far too much for the CSS, instead of just the target class:

$stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);



Anyone tell me why?


fox_stattonAsked:
Who is Participating?
 
Ray PaseurCommented:
See if this produces the final value you want.  Look at the bottom of the output.
<?php // RAY_temp_foxstatton.php
error_reporting(E_ALL);
echo "<pre>";



// $stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);



$classesbox = <<<HEREDOC
#213
#container
#global_left
HEREDOC;

$stylesheet = <<<NOTHERDOC
@charset "utf-8";
/* CSS Document */

/* */
#213 {
	PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT-FAMILY: "Helvetica Neue","Arial",sans-serif; COLOR: #213443; FONT-SIZE: 12px; PADDING-TOP: 0px
}
##2133_new {
	BACKGROUND-IMAGE: url(http://domain.com/images/bg_main.gif); TEXT-ALIGN: center; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #172531; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; BACKGROUND-REPEAT: repeat-x; BACKGROUND-POSITION: left top; PADDING-TOP: 0px
}
#container {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px; FLOAT: none
}
#global_header {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px
}
#global_center {
	TEXT-ALIGN: left; BACKGROUND-COLOR: #fff; MARGIN: 0px auto; WIDTH: 960px; CLEAR: both
}
#global_left {
	BACKGROUND-IMAGE: url('http://domain.com/images/bg_leftnav_cloud.png'); TEXT-ALIGN: left; BACKGROUND-COLOR: #36526c; MARGIN: 0px auto; WIDTH: 235px; BACKGROUND-REPEAT: repeat-y; BACKGROUND-POSITION: left top; FLOAT: left
}
NOTHERDOC;



// MAKE AN ARRAY FOR TESTING
$arr = explode(PHP_EOL, $classesbox);

// THIS SHOWS EXTRA END-OF-LINE CHARACTERS
var_dump($arr);

// CLEAN UP THE ARRAY
foreach ($arr as $k => $str)
{
    $arr[$k] = trim($str);
}

// IS THE ARRAY CLEAN? YES.
var_dump($arr);

// USE AN ITERATOR TO ACCESS EACH OF THE STRINGS IN THE $arr VARIABLE
foreach ($arr as $expr)
{
    // COPY THE STYLE SHEET
    $sheet = $stylesheet;

    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\s*?'            // SOME WHITESPACE OR NOT
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // SEE WHAT IT FINDS
    preg_match($regex, $sheet, $match);
    echo PHP_EOL . "REGEX: $regex";
    echo PHP_EOL . "MATCH: ";
    var_dump($match);
    echo PHP_EOL;
}

// COPY THE STYLE SHEET
$sheet = $stylesheet;

// USE AN ITERATOR TO ACCESS EACH OF THE STRINGS IN THE $arr VARIABLE
foreach ($arr as $expr)
{
    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\s*?'            // SOME WHITESPACE OR NOT
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // PERFORM REPLACEMENT
    $value = preg_replace($regex, NULL, $sheet);

    // SEE WHAT IT REPLACED
    echo PHP_EOL . PHP_EOL . '**************************';

    echo PHP_EOL . "REGEX: $regex";
    echo PHP_EOL . "INPUT: ";
    print_r($sheet);
    echo PHP_EOL . "VALUE: ";
    print_r($value);
    echo PHP_EOL;

    // READY FOR THE NEXT ITERATION
    $sheet = $value;
}

Open in new window

0
 
Ray PaseurCommented:
One would want to know what is in this variable:

$class_exp[$i]

You might need to use preg_quote()
0
 
Ray PaseurCommented:
Let's do this... Show us your test data, and show us the array $class_exp, as well as the iterator that generates the value of $i.  Then we can take the array, apply it to the test data and show you how to detect the output.  If we see it in action we may be able to find a way to make it "ungreedy" or otherwise modify it to suit your needs.
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
fox_stattonAuthor Commented:
Here is the code, will post test data next:
<?
$classes=$_POST['classes'];
$stylesheet=$_POST['stylesheet'];
?>
    <textarea name="stylesheet" cols="90" rows="10" id="stylesheet"><? echo $stylesheet; ?></textarea>
<?
 $class_exp=explode("\n",$classes);

for ($i=0; $i<=count($class_exp); $i++)
{

  echo "Replacing $class_exp[$i]<br />";

  // This one does not work
  //$stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);
  
    // This one works
  $stylesheet = preg_replace('/#classname \{(.*?)\}/si', '', $stylesheet);
  
} 
?>
    <textarea name="stylesheet" cols="90" rows="10" id="stylesheet"><? echo $stylesheet; ?></textarea>

Open in new window

0
 
fox_stattonAuthor Commented:
This is the form that feeds into that script, it collects a list of classes to remove and then the stylesheet
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>
<form id="form1" name="form1" method="post" action="css_proc.php">
  <p>CSS to remove</p>
  <p>
    <textarea name="classes" cols="90" rows="10" id="classes"></textarea>
    </p>
  <p>CSS style sheet</p>
  <p>
    <textarea name="stylesheet" cols="90" rows="10" id="stylesheet"></textarea>
  </p>
  <p>
    <input type="submit" name="Submit" id="Submit" value="Clean" />
</p>
</form>
</body>
</html>

Open in new window

0
 
käµfm³d 👽Commented:
I think Ray meant what kind of values are you entering in your "classes" textarea of the form you are posting  = )
0
 
Ray PaseurCommented:
I think kaufmed hit the nail on the head!
0
 
fox_stattonAuthor Commented:
Here is an example of what Im entering in the stylesheet box
@charset "utf-8";
/* CSS Document */

/* */
#213 {
	PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT-FAMILY: "Helvetica Neue","Arial",sans-serif; COLOR: #213443; FONT-SIZE: 12px; PADDING-TOP: 0px
}
##2133_new {
	BACKGROUND-IMAGE: url(http://domain.com/images/bg_main.gif); TEXT-ALIGN: center; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #172531; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; BACKGROUND-REPEAT: repeat-x; BACKGROUND-POSITION: left top; PADDING-TOP: 0px
}
#container {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px; FLOAT: none
}
#global_header {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px
}
#global_center {
	TEXT-ALIGN: left; BACKGROUND-COLOR: #fff; MARGIN: 0px auto; WIDTH: 960px; CLEAR: both
}
#global_left {
	BACKGROUND-IMAGE: url('http://domain.com/images/bg_leftnav_cloud.png'); TEXT-ALIGN: left; BACKGROUND-COLOR: #36526c; MARGIN: 0px auto; WIDTH: 235px; BACKGROUND-REPEAT: repeat-y; BACKGROUND-POSITION: left top; FLOAT: left
}

Open in new window

0
 
fox_stattonAuthor Commented:
And here is what Im entering into the classes box:
#213
#container
#global_left

Open in new window

0
 
Ray PaseurCommented:
Here is a link to my test script.   The initial run does not find anything, probably because there is a blank after the Class or Id and before the opening curly brace.   The blank is not accounted for in the regex yet.
http://www.laprbass.com/RAY_temp_foxstatton.php

While I am refining this, you might enjoy seeing the thought processes and techniques behind my work.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_7830-A-Quick-Tour-of-Test-Driven-Development.html
<?php // RAY_temp_foxstatton.php
error_reporting(E_ALL);
echo "<pre>";



// $stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);



$classesbox = <<<HEREDOC
#213
#container
#global_left
HEREDOC;

$stylesheet = <<<NOTHERDOC
@charset "utf-8";
/* CSS Document */

/* */
#213 {
	PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT-FAMILY: "Helvetica Neue","Arial",sans-serif; COLOR: #213443; FONT-SIZE: 12px; PADDING-TOP: 0px
}
##2133_new {
	BACKGROUND-IMAGE: url(http://domain.com/images/bg_main.gif); TEXT-ALIGN: center; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #172531; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; BACKGROUND-REPEAT: repeat-x; BACKGROUND-POSITION: left top; PADDING-TOP: 0px
}
#container {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px; FLOAT: none
}
#global_header {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px
}
#global_center {
	TEXT-ALIGN: left; BACKGROUND-COLOR: #fff; MARGIN: 0px auto; WIDTH: 960px; CLEAR: both
}
#global_left {
	BACKGROUND-IMAGE: url('http://domain.com/images/bg_leftnav_cloud.png'); TEXT-ALIGN: left; BACKGROUND-COLOR: #36526c; MARGIN: 0px auto; WIDTH: 235px; BACKGROUND-REPEAT: repeat-y; BACKGROUND-POSITION: left top; FLOAT: left
}
NOTHERDOC;



// MAKE AN ARRAY FOR TESTING
$arr = explode(PHP_EOL, $classesbox);

// THIS SHOWS EXTRA END-OF-LINE CHARACTERS
var_dump($arr);

// CLEAN UP THE ARRAY
foreach ($arr as $k => $str)
{
    $arr[$k] = trim($str);
}

// IS THE ARRAY CLEAN? YES.
var_dump($arr);

foreach ($arr as $expr)
{
    // COPY THE STYLE SHEET
    $sheet = $stylesheet;

    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // SEE WHAT IT FINDS
    preg_match($regex, $sheet, $match);
    var_dump($regex);
    var_dump($sheet);
    var_dump($match);
    echo PHP_EOL;
}

Open in new window

0
 
Ray PaseurCommented:
This seems to work better.  The regex matches the strings you see when you run this script.
http://www.laprbass.com/RAY_temp_foxstatton.php

Next we will try replacement and see if it does what you want.
<?php // RAY_temp_foxstatton.php
error_reporting(E_ALL);
echo "<pre>";



// $stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);



$classesbox = <<<HEREDOC
#213
#container
#global_left
HEREDOC;

$stylesheet = <<<NOTHERDOC
@charset "utf-8";
/* CSS Document */

/* */
#213 {
	PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT-FAMILY: "Helvetica Neue","Arial",sans-serif; COLOR: #213443; FONT-SIZE: 12px; PADDING-TOP: 0px
}
##2133_new {
	BACKGROUND-IMAGE: url(http://domain.com/images/bg_main.gif); TEXT-ALIGN: center; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #172531; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; BACKGROUND-REPEAT: repeat-x; BACKGROUND-POSITION: left top; PADDING-TOP: 0px
}
#container {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px; FLOAT: none
}
#global_header {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px
}
#global_center {
	TEXT-ALIGN: left; BACKGROUND-COLOR: #fff; MARGIN: 0px auto; WIDTH: 960px; CLEAR: both
}
#global_left {
	BACKGROUND-IMAGE: url('http://domain.com/images/bg_leftnav_cloud.png'); TEXT-ALIGN: left; BACKGROUND-COLOR: #36526c; MARGIN: 0px auto; WIDTH: 235px; BACKGROUND-REPEAT: repeat-y; BACKGROUND-POSITION: left top; FLOAT: left
}
NOTHERDOC;



// MAKE AN ARRAY FOR TESTING
$arr = explode(PHP_EOL, $classesbox);

// THIS SHOWS EXTRA END-OF-LINE CHARACTERS
var_dump($arr);

// CLEAN UP THE ARRAY
foreach ($arr as $k => $str)
{
    $arr[$k] = trim($str);
}

// IS THE ARRAY CLEAN? YES.
var_dump($arr);

// SHOW THE INPUT DATA (WE COPY IT FOR EVERY NEW TEST)
var_dump($stylesheet);

// USE AN ITERATOR TO ACCESS EACH OF THE STRINGS IN THE $arr VARIABLE
foreach ($arr as $expr)
{
    // COPY THE STYLE SHEET
    $sheet = $stylesheet;

    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\s*?'            // SOME WHITESPACE OR NOT
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // SEE WHAT IT FINDS
    preg_match($regex, $sheet, $match);
    echo PHP_EOL . "REGEX: $regex";
    echo PHP_EOL . "MATCH: ";
    var_dump($match);
    echo PHP_EOL;
}

Open in new window

0
 
Ray PaseurCommented:
This eliminates the CSS selector and all its attributes.  Is that what you want to do?

Thanks, ~Ray
<?php // RAY_temp_foxstatton.php
error_reporting(E_ALL);
echo "<pre>";



// $stylesheet = preg_replace('/'.$class_exp[$i].' \{(.*?)\}/si', '', $stylesheet);



$classesbox = <<<HEREDOC
#213
#container
#global_left
HEREDOC;

$stylesheet = <<<NOTHERDOC
@charset "utf-8";
/* CSS Document */

/* */
#213 {
	PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT-FAMILY: "Helvetica Neue","Arial",sans-serif; COLOR: #213443; FONT-SIZE: 12px; PADDING-TOP: 0px
}
##2133_new {
	BACKGROUND-IMAGE: url(http://domain.com/images/bg_main.gif); TEXT-ALIGN: center; PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #172531; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; BACKGROUND-REPEAT: repeat-x; BACKGROUND-POSITION: left top; PADDING-TOP: 0px
}
#container {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px; FLOAT: none
}
#global_header {
	TEXT-ALIGN: left; MARGIN: 0px auto; WIDTH: 960px
}
#global_center {
	TEXT-ALIGN: left; BACKGROUND-COLOR: #fff; MARGIN: 0px auto; WIDTH: 960px; CLEAR: both
}
#global_left {
	BACKGROUND-IMAGE: url('http://domain.com/images/bg_leftnav_cloud.png'); TEXT-ALIGN: left; BACKGROUND-COLOR: #36526c; MARGIN: 0px auto; WIDTH: 235px; BACKGROUND-REPEAT: repeat-y; BACKGROUND-POSITION: left top; FLOAT: left
}
NOTHERDOC;



// MAKE AN ARRAY FOR TESTING
$arr = explode(PHP_EOL, $classesbox);

// THIS SHOWS EXTRA END-OF-LINE CHARACTERS
var_dump($arr);

// CLEAN UP THE ARRAY
foreach ($arr as $k => $str)
{
    $arr[$k] = trim($str);
}

// IS THE ARRAY CLEAN? YES.
var_dump($arr);

// SHOW THE INPUT DATA (WE COPY IT FOR EVERY NEW TEST)
var_dump($stylesheet);

// USE AN ITERATOR TO ACCESS EACH OF THE STRINGS IN THE $arr VARIABLE
foreach ($arr as $expr)
{
    // COPY THE STYLE SHEET
    $sheet = $stylesheet;

    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\s*?'            // SOME WHITESPACE OR NOT
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // SEE WHAT IT FINDS
    preg_match($regex, $sheet, $match);
    echo PHP_EOL . "REGEX: $regex";
    echo PHP_EOL . "MATCH: ";
    var_dump($match);
    echo PHP_EOL;
}

// USE AN ITERATOR TO ACCESS EACH OF THE STRINGS IN THE $arr VARIABLE
foreach ($arr as $expr)
{
    // COPY THE STYLE SHEET
    $sheet = $stylesheet;

    // CONSTRUCT THE REGEX
    $regex
    = '/'               // REGEX DELIMITER
    . preg_quote($expr) // THE EXTERNAL DATA
    . '\s*?'            // SOME WHITESPACE OR NOT
    . '\{'              // AN ESCAPED CURLY BRACE
    . '(.*?)'           // A GROUP OF SOMETHING OR NOTHING
    . '\}'              // AN ESCAPED CURLY BRACE
    . '/'               // REGEX DELIMITER
    . 's'               // STRING AS LINE
    . 'i'               // CASE INSENSITIVE
    ;

    // PERFORM REPLACEMENT
    $value = preg_replace($regex, NULL, $sheet);

    // SEE WHAT IT REPLACED
    echo PHP_EOL . PHP_EOL . '**************************';

    echo PHP_EOL . "REGEX: $regex";
    echo PHP_EOL . "INPUT: ";
    print_r($sheet);
    echo PHP_EOL . "VALUE: ";
    print_r($value);
    echo PHP_EOL;
}

Open in new window

0
 
fox_stattonAuthor Commented:
Hi Ray,
Yes, Id like it to remove the CSS class and attributes, but Ive just tested that script, and they dont seem to be being removed, for example class #213 is still there,

Thanks
0
 
käµfm³d 👽Commented:
You should use preg_quote as Ray indicated (and demonstrated). Also, in my testing, it appeared that the incoming class names had spaces on the end after the explode. It could just be something I was doing incorrectly. You may want to trim those values before passing them to the regex. I'd also suggest changing your delimiter since the forward slash occurs in your target text.

Try this:

$stylesheet = preg_replace('|'.preg_quote(trim($class_exp[$i])).' \{(.*?)\}|si', '', $stylesheet);

Open in new window

0
 
käµfm³d 👽Commented:
Correction:

$stylesheet = preg_replace('|'.preg_quote(trim($class_exp[$i])).' \s*\{(.*?)\}|si', '', $stylesheet);

Open in new window

0
 
Ray PaseurCommented:
Ive just tested that script

If you tested the script that I wrote, you may find that it tests each of the removal processes separately on a copy of the style sheet.  You can just stop copying the stylesheet for each test, and apply all the REGEX in order, right?
0
 
fox_stattonAuthor Commented:
Fantastic, thank you!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.