Php 用正则表达式解析CSS

Php 用正则表达式解析CSS,php,css,regex,css-parsing,Php,Css,Regex,Css Parsing,我正在创建一个CSS编辑器,并试图创建一个可以从CSS文档中获取数据的正则表达式。如果我有一个属性,这个正则表达式可以工作,但是我不能让它对所有属性都工作。我在PHP中使用preg/perl语法 正则表达式 预期结果 实际结果 提前感谢您的帮助-整个下午我都很困惑 对于单个正则表达式来说,这似乎太复杂了。好吧,我相信有了正确的扩展,高级用户可以创建正确的正则表达式。但是你需要一个更高级的用户来调试它 相反,我建议使用正则表达式提取片段,然后分别标记每个片段。e、 g /([^{])\s*\{\s

我正在创建一个CSS编辑器,并试图创建一个可以从CSS文档中获取数据的正则表达式。如果我有一个属性,这个正则表达式可以工作,但是我不能让它对所有属性都工作。我在PHP中使用preg/perl语法

正则表达式 预期结果 实际结果
提前感谢您的帮助-整个下午我都很困惑

对于单个正则表达式来说,这似乎太复杂了。好吧,我相信有了正确的扩展,高级用户可以创建正确的正则表达式。但是你需要一个更高级的用户来调试它

相反,我建议使用正则表达式提取片段,然后分别标记每个片段。e、 g

/([^{])\s*\{\s*([^}]*?)\s*}/

然后,将选择器和属性放在单独的字段中,然后将它们拆分。(即使是选择器解析起来也很有趣。)请注意,如果}出现在引号或其他内容中,即使这样也会带来麻烦。同样,您可以将其复杂化以避免这种情况,但在这里最好完全避免正则表达式,并通过一次解析一个字段来处理它,可能使用递归下降解析器或yacc/bison或其他任何方法。

您试图从数据中提取结构,而不仅仅是单个值。正则表达式可能会被痛苦地拉伸以完成这项工作,但您实际上正在进入解析器领域,应该拿出大炮,即解析器


我从来没有使用过PHP解析器生成工具,但它们在轻松扫描文档后看起来还不错。退房并离开。LexerGenerator将使用一组正则表达式来描述一种语言(在本例中为CSS)中不同类型的标记,并输出一些识别单个标记的代码。ParserGenerator将获取一个语法,一个描述语言中哪些东西由哪些其他东西组成的描述,并输出一个解析器,一个代码,该代码将获取一组标记并返回一个语法树(您所追求的数据结构)。

我建议不要使用正则表达式来解析CSS,尤其是在单个正则表达式中

如果您坚持在正则表达式中进行解析,请将其拆分为合理的部分-使用一个正则表达式拆分所有
body{..}
块,然后使用另一个正则表达式解析
color:rgb(1,2,3);
属性

如果您实际上正在尝试编写一些“有用”的东西(而不是学习正则表达式),请寻找预先编写的CSS解析器

我发现这似乎很有效:

$cssp = new cssparser;
$cssp -> ParseStr("body { background: #f00;font: 12px Arial; }");
print_r($cssp->css);
…其输出如下:

Array
(
    [body] => Array
        (
            [background] => #f00
            [font] => 12px arial
        )
)
解析器非常简单,所以应该很容易理解它在做什么。哦,我不得不删除读取
if($this->html){$this->Add($VAR),”;}
(这似乎是一个遗留的调试内容)


我已经镜像了脚本,在上面的更改中,请不要使用您自己的正则表达式来解析CSS。 为什么要在代码等着你、准备好使用并且(希望)没有bug的时候重新发明轮子呢

有两个通常可用的类可以为您解析CSS:

PEAR.php.net上的HTML_CSS PEAR包

PHPCLasses上的CSS解析器类:


我正在使用下面的正则表达式,它非常有效……当然,这个问题现在已经很老了,我看到你已经放弃了你的努力……但万一有人碰到它:

(?<selector>(?:(?:[^,{]+),?)*?)\{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?\}
(?(?:(?:[^,{]+,?)*?)\{((?[^}::+):(?[^;]+);?)*?\}
(为了安全起见,hafta首先从CSS中删除所有的/*注释*/

试试这个

function trimStringArray($stringArray){
    $result = array();
    for($i=0; $i < count($stringArray); $i++){
        $trimmed = trim($stringArray[$i]);
        if($trimmed != '') $result[] = $trimmed;
    }
    return $result;
}
$regExp = '/\{|\}/';
$rawCssData = preg_split($regExp, $style);

$cssArray = array();
for($i=0; $i < count($rawCssData); $i++){
    if($i % 2 == 0){
        $cssStyle['selectors'] = array();
        $selectors = split(',', $rawCssData[$i]);
        $cssStyle['selectors'] = trimStringArray($selectors);
    }
    if($i % 2 == 1){
        $attributes = split(';', $rawCssData[$i]);
        $cssStyle['attributes'] = trimStringArray($attributes);
        $cssArray[] = $cssStyle;
    }

}
//return false;
echo '<pre>'."\n";
print_r($cssArray);
echo '</pre>'."\n";
函数trimStringArray($stringArray){
$result=array();
对于($i=0;$i
我写了一段很容易解析CSS的代码。你所要做的就是进行几次分解,实际上,$CSS变量是CSS的一个字符串。你所要做的就是打印($CSS)以获得一个完整解析的CSS数组

Array
(
    [body] => Array
        (
            [background] => #f00
            [font] => 12px arial
        )
)

在Tanktalus当前答案的基础上,有几个改进和边缘案例需要注意

CSS解析正则表达式 此正则表达式将执行一些空间修剪,并点击一些额外的边缘情况,如本例所示:

键:值对;进一步复杂化正则表达式的陷阱 我也开始尝试划分key:value对,但很快发现,在每个选择器有多个样式的情况下,事情开始变得比我想要的更棘手。您可以在这里查看我尝试划分key:value的regex版本1,以及它如何在多个声明中失败:

实施 正如其他人提到的,您应该将其分解为多个步骤来解析和标记您的css

声明解析器 在获得第一组匹配项后,可以使用类似这样的方法来解析声明

([^:\s]+)*\s*:\s*([^;]+);

例如:

边缘案例 上面的示例对于多个声明非常有效,但可能只有一个声明没有分号结尾,这将在[大多数]浏览器中呈现,但会破坏这个正则表达式

著名案例 在有媒体查询的情况下,您可能还需要考虑嵌套规则
Array
(
    [body] => Array
        (
            [background] => #f00
            [font] => 12px arial
        )
)
(?<selector>(?:(?:[^,{]+),?)*?)\{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?\}
function trimStringArray($stringArray){
    $result = array();
    for($i=0; $i < count($stringArray); $i++){
        $trimmed = trim($stringArray[$i]);
        if($trimmed != '') $result[] = $trimmed;
    }
    return $result;
}
$regExp = '/\{|\}/';
$rawCssData = preg_split($regExp, $style);

$cssArray = array();
for($i=0; $i < count($rawCssData); $i++){
    if($i % 2 == 0){
        $cssStyle['selectors'] = array();
        $selectors = split(',', $rawCssData[$i]);
        $cssStyle['selectors'] = trimStringArray($selectors);
    }
    if($i % 2 == 1){
        $attributes = split(';', $rawCssData[$i]);
        $cssStyle['attributes'] = trimStringArray($attributes);
        $cssArray[] = $cssStyle;
    }

}
//return false;
echo '<pre>'."\n";
print_r($cssArray);
echo '</pre>'."\n";
$css_array = array(); // master array to hold all values
$element = explode('}', $css);
foreach ($element as $element) {
    // get the name of the CSS element
    $a_name = explode('{', $element);
    $name = $a_name[0];
    // get all the key:value pair styles
    $a_styles = explode(';', $element);
    // remove element name from first property element
    $a_styles[0] = str_replace($name . '{', '', $a_styles[0]);
    // loop through each style and split apart the key from the value
    $count = count($a_styles);
    for ($a=0;$a<$count;$a++) {
        if ($a_styles[$a] != '') {
            $a_key_value = explode(':', $a_styles[$a]);
            // build the master css array
            $css_array[$name][$a_key_value[0]] = $a_key_value[1];
        }
    }               
}
Array
(
    [body] => Array
        (
            [background] => #f00
            [font] => 12px arial
        )
)
\s*([^{]+)\s*\{\s*([^}]*?)\s*}