0

i need some help with a RegEx that should split cssText( not selector,but the part inside {} ) into assoc with key->value pairs array in PHP

Assuming the the selector part is removed and there is for instance this:

color: black;
font-family: \"Courier New\";
background: url(\"test.png\");
color: red;

Yes the string is escaped i did managed to do that when extracting the {} part.

BUT:

if background is dataURI or there is content prop set like those:

content:'1.test;2.blabla;';
background: white url('data:image/png;base64,iVBORw0KGgoAA
AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABl...') no-repeat scroll left top;

the splitting RegEx i use:

preg_match_all('/([\w-]+)\s*:\s*([^;]*)\s*;?/i', $css, $matches, PREG_SET_ORDER);

fails :(

I'm not pro in RegEx and need your advice on how to NOT brake on ';' appearance inside \"...\" inside the string.

It should be in the capturing group ([^;]*) which as i found means: Match any single character that is not ; and repeat that 0 or more times.

Thanks in advance!

Kkart
  • 357
  • 1
  • 2
  • 10
  • 1
    Does it need to be regular expression? or any solution is acceptable? – invisal Aug 27 '13 at 09:34
  • I've made some regex at this post, which does not some code to work not only regex: http://stackoverflow.com/questions/12872879/how-to-convert-css-string-into-array/12872969#12872969 – Niels Aug 27 '13 at 09:35
  • If you want to play with CSS and regex this could be relevant: http://stackoverflow.com/questions/15195750/minify-compress-css-with-regex – Qtax Aug 27 '13 at 09:35
  • 1
    can be anything that works in PHP... – Kkart Aug 27 '13 at 09:36

4 Answers4

1

If this is not for learning purposes, I really would recommend using a library instead of re-inventing the wheel :) Something like https://github.com/sabberworm/PHP-CSS-Parser.

Markus Hedlund
  • 23,374
  • 22
  • 80
  • 109
  • I don't want to use a parser because the CSS is already validated, comments are stripped and so on...it only needs to be spitted for further usage. thanks anyway! – Kkart Aug 27 '13 at 09:57
  • @LiliputFX You would save *so* much time. If you still want to implement it yourself, I'd suggest [looking at the CSS 2.1 spec](http://www.w3.org/TR/2011/REC-CSS2-20110607/) so you don't miss anything. – Markus Hedlund Aug 27 '13 at 10:05
1

Use this function

function BreakCSS($CSS) {
    $results = array();

    foreach(explode(';', $CSS) AS $attr)
        if (strlen(trim($attr)) > 0) // for missing semicolon on last element, which is legal
        {
            list($name, $value) = explode(':', $attr);
            $results[trim($name)] = trim($value);
        }
    return $results;
}
iProDev
  • 547
  • 6
  • 5
0

If you don't care about comments you could use something like this to handle quoted content with escapes:

/([\w-]++) \s*+ : \s*+ ( (?: [^;'"]++ | "(?:[^"\\]|\\.)*+" | '(?:[^'\\]|\\.)*+' )*+ ) \s* ;?/x

(Don't forget to double+ escape the \\ when quoting in PHP.)

Qtax
  • 33,241
  • 9
  • 83
  • 121
0

I am crafting a simple parseCSS function using a simple state machine. You can read the code and you can extend further to what you need. The complexity of the algorihm is O(N) where N is the length of the css.

function parseCSS($css)
{
    // State variable
    $isOption = true; $isValue = false; $isQuote = ''; $arr=array();

    // Buffer variable
    $option = ''; $value = '';

    for($i = 0; $i < strlen($css); $i++) {
        if ($isOption) {
            if ($css[$i] == ':') {
                $isValue = true; $isOption = false;
            } else {
                $option .= $css[$i];
            }
        } elseif ($isValue) {
            if ($isQuote == $css[$i]) {
                $isQuote = ''; $value .= $css[$i];
            } elseif ($isQuote != '') {
                $value .= $css[$i];
            } else {
                if (($css[$i] == "'") || ($css[$i] == '"')) {
                    $isQuote = $css[$i]; $value .= $css[$i];
                } elseif ($css[$i] == ';') {
                    $arr[trim($option)] = trim($value);
                    $option = ''; $value = '';
                    $isOption = true; $isValue = false;
                } else {
                    $value .= $css[$i];
                }
            }
        }
    }

    return $arr;
}

$css = parseCSS
(
    "content:'1.test;2.blabla;';
    background: white url('data:image/png;base64,iVBORw0KGgoAA
    AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABl...') no-repeat scroll left top;"
);

var_dump($css);
Kkart
  • 357
  • 1
  • 2
  • 10
invisal
  • 11,075
  • 4
  • 33
  • 54