2

Hey. I'm trying to parse a CSS file using PHP.

I'm trying to run this expression:

"/(". $selector . "\\s*{[\\w\\s:\\-;()#]*)(" . $property . ":)([^;}]+)(}?)/Ui"

This regex is supposed to pin down a specific property within a selector and allow me to change it's value/remove it.

rational:

  1. match the selector and it's text preceding to the property
  2. match the property name
  3. match the property value
  4. if the value ends by the } sign - catch it as well

The broken bit is #3 - For some unknown reason, when I run this through preg_match, the value group(#3) only catches the first char.

For example, running this expression:

preg_replace("/(h1\s*{[\w\s:\-;()#]*)(font-size:)(([^;}])+)(}?)/Ui","$1 $4",$css);

(find the font-size property of the h1 selector, and remove the property and value)

on this css group:

h1{
    background:#fff;
    font-size:10px;
    text-align:underline;
    color:#abc;
}

I get:

h1{
    background:#fff;
    /* note that although the property was matched and removed,
       the value only matched the 1st char: 1 */ 
    0px; 
    text-align:underline;
    color:#abc;
}

I've tried to check the expression through some test tools and it worked fine, so I'm guessing this is a preg* specific problem.

any ideas what I'm doing wrong?

2
  • 3
    parse a CSS file using CSS ? Maybe you mean PHP? :) And it might help to explain what you actually want to achieve and what the regex does. Commented Jan 15, 2011 at 18:59
  • why are you trying to change css with regex?? seems backwards. why not just make the entire css file a .php file, and dynamically set the style to whatever you want? Commented Jan 15, 2011 at 19:28

4 Answers 4

1

Parsing CSS only with regexp is masochism.

You can find some information how to parse CSS in this CSS object model specification. Sorry I was able to find only Editor's draft, the other URLs seems to be broken.

Sign up to request clarification or add additional context in comments.

Comments

0

(([^;}])+)(}?) does actually match only one char (with modifier U).

You have to use something like this: ([^;}]+)(;|})

Additionally it's not bad to escape curly braces.

The full RegEx:

preg_replace('/('.$selector.'\s*\{[\w\s:\-;\(\)#]*)('.$property.'\s*:)([^;\}]+)(;|\})/Ui', '$1 $4', $css);

1 Comment

the thing is - I want to only capture the } so that I can prepend it to the statement... Any good way of doing this?
0

dont regroup the 3rd brackets, try:

preg_replace("/(h1\s*{[\w\s:\-;()#]*)(font-size\s*:)([^;}]+)(}?)/Ui","$1 $4",$css);

in addition, i added \s* after the property, to allow it to catch things like

font-size : 10px

1 Comment

nope. still no results (thought the \s addition is adopted :) )
0

Your torturing yourself with the "ungreedy" modifier '/U', I wouldn't use it.
The real problem is that you are making provisions for 'property:value' ending to be either a ';' or a '}'

So, it can be either [;}] that is your final delimeter. There is really no easy way to implement that while preserving the formatting, I redid your regex a little. Think php does Perl compatible regex, so rearranged and doctored up the last part to a reasonable working model. Its not for the faint of heart.

The modifiers are Perl's /xi stands for expanded and case insensitive.
Don't use php's /U modifier on this! There is only 2 capture groups now, 1 & 2.

Regex as unquoted with variables:

/((?:$selector)\s*\{[\w\s:;()#-]*?)\s*(?:$property)\s*:(?:(?!\s*\})[^;])+(?:(?=;);[^\S\n]*)?(\s*\}?)/i;

Regex catted as a string:

'/((?:' . $selector . ')\s*\{[\w\s:;()#-]*?)\s*(?:' . $property. ')\s*:(?:(?!\s*\})[^;])+(?:(?=;);[^\S\n]*)?(\s*\}?)/xi;'

Test case in Perl:

use strict;
use warnings;

my ($selector, $property) = ( 'h1 | h2', 'font-size' );

my $sample = 
'
h1{
    background:#fff;
    font-size:10px;
    text-align:underline;
    color:#abc;
}
h2{
    text-align:strikethrough;
    background:#fefe;
    color:#dbd;
    font-size:10px
} ';

my $rx = qr/
  (                      # group 1
      (?:$selector)
      \s*
      \{
         [\w\s:;()#-]*?
  )
         \s* (?:$property) \s*: (?: (?!\s*\}) [^;] )+
         (?:
             (?=;) ;[^\S\n]*
         )?
  (                      # group 2
      \s*
      \}?
  )
/xi;

print $rx,"\n\n";

$sample =~ s/$rx/$1$2/g;

print $sample,"\n";

Output:

(?ix-sm:
  (                      # group 1
      (?:h1 | h2)
      \s*
      \{
         [\w\s:;()#-]*?
  )
         \s* (?:font-size) \s*: (?: (?!\s*\}) [^;] )+
         (?:
             (?=;) ;[^\S\n]*
         )?
  (                      # group 2
      \s*
       \}?
  )
)

h1{
    background:#fff;
    text-align:underline;
    color:#abc;
}
h2{
    text-align:strikethrough;
    background:#fefe;
    color:#dbd;
}
/((?:h1 | h2)\s*\{[\w\s:;()#-]*?)\s*(?:font-size)\s*:(?:(?!\s*\})[^;])+(?:(?=;);[^\S\n]*)?(\s*\}?)/xi;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.