我想用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文件。只要它不贪心,就不能防弹
答案 0 :(得分:11)
这应该这样做:
<?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,那么除了最简单的“任何{任何东西}”之外你没有必要做任何事情。 。取决于你想用它做什么,真的。
答案 1 :(得分:6)
如果您对具有多选择器和分隔线的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 {...}
答案 2 :(得分:3)
如果我是你,我会为CSS构建(或找到)一个真正的语法,并以这种方式进行解析。试图为任何非平凡的表达式语言编写一个解析器(而CSS显然不是微不足道的,所有花哨的选择器)让我遇到麻烦的时间超过了足够多。
示例:http://www.phpclasses.org/package/1289-PHP-CSS-parser-class.html
答案 3 :(得分:0)
我建议answer of inakiabt中的选择器ng-if
以获得更好的解决方案。
答案 4 :(得分:0)
我也会添加我的解决方案。我不得不将一个包含所有媒体查询的大型 css 文件拆分为单独的文件,因此页面速度的移动评级提高了 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);