【问题标题】:Break a CSS file into an array with PHP使用 PHP 将 CSS 文件分解为数组
【发布时间】: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 文件。只要不贪心,就不一定是防弹的

【问题讨论】:

  • 糟糕,我写了一些相反的东西。

标签: php css regex parsing


【解决方案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
        • 注释规则失败:-(
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-26
        • 1970-01-01
        • 1970-01-01
        • 2017-12-19
        • 2011-04-06
        • 2012-06-22
        • 1970-01-01
        相关资源
        最近更新 更多