php - Análisis CSS por regex
css-parsing (7)
Está tratando de sacar la estructura de los datos, y no solo los valores individuales. Las expresiones regulares pueden ser muy estirado para hacer el trabajo, pero en realidad estás entrando en el territorio del analizador sintáctico, y debes sacar las armas grandes, es decir, los analizadores sintácticos.
Nunca he usado las herramientas de generación de analizadores de PHP, pero se ven bien después de un escaneo de luz de los documentos. Consulte LexerGenerator y ParserGenerator . LexerGenerator tomará un montón de expresiones regulares que describen los diferentes tipos de tokens en un idioma (en este caso, CSS) y escupirá algún código que reconozca los tokens individuales. ParserGenerator tomará una gramática, una descripción de qué cosas en un idioma están compuestas de qué otras cosas, y escupirá un analizador, código que toma un montón de tokens y devuelve un árbol de sintaxis (la estructura de datos que está buscando.
Estoy creando un editor de CSS y estoy tratando de crear una expresión regular que pueda obtener datos de un documento CSS. Esta expresión regular funciona si tengo una propiedad pero no puedo hacer que funcione para todas las propiedades. Estoy usando sintaxis preg / perl en PHP.
Regex
(?<selector>[A-Za-z]+[/s]*)[/s]*{[/s]*((?<properties>[A-Za-z0-9-_]+)[/s]*:[/s]*(?<values>[A-Za-z0-9#, ]+);[/s]*)*[/s]*}
Caso de prueba
body { background: #f00; font: 12px Arial; }
Gastos esperados
Array(
[0] => Array(
[0] => body { background: #f00; font: 12px Arial; }
[selector] => Array(
[0] => body
)
[1] => Array(
[0] => body
)
[2] => font: 12px Arial;
[properties] => Array(
[0] => font
)
[3] => Array(
[0] => font
)
[values] => Array(
[0] => 12px Arial
[1] => background: #f00
)
[4] => Array(
[0] => 12px Arial
[1] => background: #f00
)
)
)
Resultado real
Array(
[0] => Array
(
[0] => body { background: #f00; font: 12px Arial; }
[selector] => body
[1] => body
[2] => font: 12px Arial;
[properties] => font
[3] => font
[values] => 12px Arial
[4] => 12px Arial
)
)
Gracias de antemano por cualquier ayuda, ¡esto me ha estado confundiendo toda la tarde!
Recomendaría no usar expresiones regulares para analizar CSS, ¡especialmente en expresiones regulares únicas!
Si insiste en hacer el análisis sintáctico en expresiones regulares, divídalo en secciones sensibles: use una expresión regular para dividir todos los bloques del body{..}
, luego otra para analizar el color:rgb(1,2,3);
atributos.
Si realmente está tratando de escribir algo "útil" (no tratando de aprender expresiones regulares), busque un analizador de CSS preescrito.
Encontré este cssparser.php que parece funcionar muy bien:
$cssp = new cssparser;
$cssp -> ParseStr("body { background: #f00;font: 12px Arial; }");
print_r($cssp->css);
..que produce lo siguiente:
Array
(
[body] => Array
(
[background] => #f00
[font] => 12px arial
)
)
El analizador es bastante simple, por lo que debería ser fácil determinar qué está haciendo. Oh, tuve que eliminar las líneas que leen if($this->html) {$this->Add("VAR", "");}
(parece ser una depuración lo que quedaba)
He duplicado el guión aquí , con los cambios anteriores en
No use su propia expresión regular para analizar CSS. ¿Por qué reinventar la rueda mientras hay código esperando por ti, listo para usar y (con suerte) libre de errores?
Hay dos clases generalmente disponibles que pueden analizar CSS para usted:
Paquete HTML_CSS PEAR en pear.php.net
y
Clase de analizador de CSS en PHPCLasses:
Prueba esto
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";
Estoy usando la expresión regular a continuación y funciona bastante ... por supuesto, esta pregunta es antigua y veo que has abandonado tus esfuerzos ... pero en caso de que alguien más se encuentre con ella:
(?<selector>(?:(?:[^,{]+),?)*?)/{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?/}
(Debe eliminar todos los / * comentarios * / de su CSS primero para estar seguro)
Escribí un fragmento de código que analiza fácilmente CSS. Todo lo que tienes que hacer es hacer un par de explosiones realmente ... La variable $ css es una cadena de CSS. Todo lo que tienes que hacer es print_r($css)
para obtener una buena matriz de CSS, completamente analizada.
$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];
}
}
}
Te da esto:
Array
(
[body] => Array
(
[background] => #f00
[font] => 12px arial
)
)
Eso solo parece demasiado enrevesado para una sola expresión regular. Bueno, estoy seguro de que con las extensiones correctas, un usuario avanzado podría crear la expresión regular correcta. Pero luego necesitarías un usuario aún más avanzado para depurarlo.
En cambio, sugiero usar una expresión regular para extraer las piezas, y luego tokenizar cada pieza por separado. p.ej,
/([^{])/s*/{/s*([^}]*?)/s*}/
Luego terminas con el selector y los atributos en campos separados, y luego los divides. (Incluso el selector será divertido de analizar.) Tenga en cuenta que incluso esto tendrá dolores si} pueden aparecer dentro de comillas o algo así. Podrías, otra vez, complicarse al máximo para evitar eso, pero probablemente sea mejor evitar las expresiones regulares por completo aquí, y manejarlo analizando un campo a la vez, quizás usando un analizador sintáctico de descenso recursivo o yacc / bison o lo que sea.