使用 PHP 将 CSS 文件分解为数组

Posted

技术标签:

【中文标题】使用 PHP 将 CSS 文件分解为数组【英文标题】:Break a CSS file into an array with PHP 【发布时间】:2010-11-15 22:48:05 【问题描述】:

我想用 php 将一个 css 文件分解成一个数组。

例如:

#selector display:block; width:100px; 
#selector a float:left; text-decoration:none; 

放入一个php数组...

array(2) 
  ["#selector"] => array(2) 
    [0] => array(1) 
      ["display"] => string(5) "block"
    
    [1] => array(1) 
      ["width"] => string(5) "100px"
    
  
  ["#selector a"] => array(2) 
    [0] => array(1) 
      ["float"] => string(4) "left"
    
    [1] => array(1) 
      ["text-decoration"] => string(4) "none"
    
  

有什么想法吗?

哦:编辑:在这种情况下,我不担心格式错误的 CSS 文件。只要不贪心,就不一定是防弹的

【问题讨论】:

糟糕,我写了一些相反的东西。 【参考方案1】:

我还将添加我的解决方案。我不得不将一个包含所有媒体查询的大型 css 文件拆分为单独的文件,因此 pagespeed 上的移动评分上升了 10 分,因为它不需要等待整个大型 css 文件。

输出是一个按媒体查询拆分的数组。

$path = 'my-css-file.css'
$css = file_get_contents($path);
$cleanCss = [];

// Remove css comments
$clean1 = explode('/*', $css);
foreach($clean1 as $clean2) 
    $clean3 = explode('*/', $clean2);
    $cleanCss[] = $clean3[count($clean3) -1];

$css = implode('', $cleanCss);
$temp = explode('', $css);
$params = [];
$type = 'all';
$nextBracketIsNotMediaEnd = false;
foreach($temp as $tem2) 
    $data = explode('', $tem2);
    if (count($data) == 1) 
        if ($nextBracketIsNotMediaEnd) 
            $nextBracketIsNotMediaEnd = false;
         else 
            $type = 'all';
            continue;
        
    
    if (count($data) == 3) 
        $typeTemp = trim($data[0]);
        if (substr( $typeTemp, 0, 6 ) === "@media" ) 
            $type = $typeTemp;
            array_shift($data);
         else 
            $data[1] = $data[0].$data[1];
            $nextBracketIsNotMediaEnd = true;
        
    
    if (count($data) == 2) 
        $rows = explode(';',$data[1]);

        $tempData = [];
        foreach($rows as $row) 
            $paramsinline = explode(':', $row);
            if (empty($paramsinline[0]) || empty($paramsinline[1]))
                continue;
            
            $tempData[trim($paramsinline[0])] = trim($paramsinline[1]);
        
        $selector = trim($data[0]);
        if (!empty($tempData)) 
            if (empty($params[$type][$selector])) 
                $params[$type][$selector] = $tempData;
             else 
                $params[$type][$selector] = array_merge($params[$type][$selector], $tempData);
            
        
    


// Here you have the output, splitted by media queries
print_r($params);

【讨论】:

【参考方案2】:

我建议answer of inakiabt 中的选择器(?ims)([a-z0-9\s\,\.\:#_\-@*()\[\]"=]+)\([^\]*)\ 以获得更好的解决方案。

【讨论】:

【参考方案3】:

如果您需要相同的 CSS 规则与多重选择器和断线:

<?php                      
$css = "
#selector
 display:block; 
width:100px; 

#selector a:hover div.asd, #asd h1.asd  
float:left; 
text-decoration:none; 

";
preg_match_all( '/(?ims)([a-z0-9\s\,\.\:#_\-@]+)\([^\]*)\/', $css, $arr);

$result = array();
foreach ($arr[0] as $i => $x)

    $selector = trim($arr[1][$i]);
    $rules = explode(';', trim($arr[2][$i]));
    $result[$selector] = array();
    foreach ($rules as $strRule)
    
        if (!empty($strRule))
        
            $rule = explode(":", $strRule);
            $result[$selector][][trim($rule[0])] = trim($rule[1]);
        
    
   

var_dump($result);
?>

输出:

array(2) 
  ["#selector"]=>
  array(2) 
    [0]=>
    array(1) 
      ["display"]=>
      string(5) "block"
    
    [1]=>
    array(1) 
      ["width"]=>
      string(5) "100px"
    
  
  ["#selector a:hover div.asd, #asd h1.asd"]=>
  array(2) 
    [0]=>
    array(1) 
      ["float"]=>
      string(4) "left"
    
    [1]=>
    array(1) 
      ["text-decoration"]=>
      string(4) "none"
    
  

更新:添加了对多个选择器的支持,例如:.box、.element、div ...

【讨论】:

如果选择器为多个,则无法正常工作:.box、.element、div ... 很好,但不适用于 background-image: url("data:image/png;base64,........ 类型的值.. 这是否适用于引导程序的@media。我尝试使用它,但它肯定会忽略。【参考方案4】:

如果我是你,我会为 CSS 构建(或找到)一个真正的语法,并以这种方式进行解析。尝试为任何非平凡的表达式语言编写解析器(CSS 显然不是平凡的,所有花哨的选择器)让我陷入麻烦的次数已经够多了。

示例:http://www.phpclasses.org/package/1289-PHP-CSS-parser-class.html

【讨论】:

【参考方案5】:

应该这样做:

<?php

$css = <<<CSS
#selector  display:block; width:100px; 
#selector a  float:left; text-decoration:none 
CSS;

//
function BreakCSS($css)


    $results = array();

    preg_match_all('/(.+?)\s?\\s?(.+?)\s?\/', $css, $matches);
    foreach($matches[0] AS $i=>$original)
        foreach(explode(';', $matches[2][$i]) AS $attr)
            if (strlen(trim($attr)) > 0) // for missing semicolon on last element, which is legal
            
                list($name, $value) = explode(':', $attr);
                $results[$matches[1][$i]][trim($name)] = trim($value);
            
    return $results;

var_dump(BreakCSS($css));

快速说明:正则表达式简单而无聊。它只匹配所有“任何东西,可能的空格,花括号,可能的空格,任何东西,闭合花括号”。从那里开始,第一个匹配是选择器,第二个匹配是属性列表。用分号分割,剩下的就是键/值对。里面有一些 trim() 来去除空格,就是这样。

我猜您的下一个最佳选择可能是用逗号分解选择器,以便您可以合并适用于同一事物等的属性,但我会为您保存。 :)

编辑:如上所述,真正的语法解析器会更实用......但如果你假设 CSS 格式正确,那么除了最简单的“任何东西 任何东西 ”之外,没有理由需要做任何事情.真的,这取决于你想用它做什么。

【讨论】:

..sexplode() 嗯?我仔细检查了一下手册:P 我已经在我的一个项目的迁移过程中将其翻译成 Python,如果您有兴趣,check it out。 注释规则失败:-(

以上是关于使用 PHP 将 CSS 文件分解为数组的主要内容,如果未能解决你的问题,请参考以下文章

Eigen解线性方程组

PHP 将URLS的文本文件分解为HTML链接

将字符串分解为具有2个分隔符的多数组

PHP 块 - 将大型XML文件分解为可管理块

PHP:将 textarea 行分解为单独的数组元素

matlab里矩阵的正交分解怎么表示