Regex ile Ayrıştırma CSS

7 Cevap php

Ben bir CSS editörü kuruyorum ve CSS belgeden veri almak, düzenli bir ifade oluşturmak için çalışıyorum. Ben bir özelliği var ama tüm özellikleri için işe alınamıyor Bu regex çalışır. PHP gebelik / perl sözdizimi kullanıyorum.

Regex

(?<selector>[A-Za-z]+[\s]*)[\s]*{[\s]*((?<properties>[A-Za-z0-9-_]+)[\s]*:[\s]*(?<values>[A-Za-z0-9#, ]+);[\s]*)*[\s]*}

Test case

body { background: #f00; font: 12px Arial; }

Expected Outcome

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
            )
        )
)

Real Outcome

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
        )
    )

Teşekkür peşin herhangi bir yardım için - bu bana bütün öğleden sonra kafa karıştırıcı oldu!

7 Cevap

Bu sadece tek bir düzenli ifade için çok dolambaçlı görünüyor. Eh, ben doğru genişletmeleri ile, gelişmiş bir kullanıcı doğru regex oluşturabilir olabilir emin değilim. Ama sonra bunu ayıklamak için daha da gelişmiş bir kullanıcı gerekiyordu.

Bunun yerine, ben parçaları dışarı çekmek için bir regex kullanarak, ve sonra ayrı ayrı her bir parça tokenising öneririm. örneğin,

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

Sonra ayrı alanlarda seçici ve nitelikleri ile sonuna kadar, ve daha sonra bu ayrıldı. (Hatta seçici ayrıştırmak için eğlenceli olacak.) 'Nin tırnak falan içinde görünebilir} bile bu ağrıları var unutmayın. Sen, yine, bu önlemek için bunun dışında halt dürülmüş olabilir, ama burada tamamen regex en önlemek için muhtemelen daha iyi, ve belki de bir özyinelemeli-iniş ayrıştırıcı veya yacc / bizon veya kullanarak, bir kerede tek bir alan ayrıştırma tarafından ele ne olursa olsun.

Sadece bireysel değerleri değil, verilerin dışarı yapısını çekmeye çalışıyoruz, ve vardır. Düzenli ifadeler acı işi yapmak için gergin olabilir olabilir, ama sen gerçekten ayrıştırıcı topraklarına giriyoruz ve büyük silah, yani ayrıştırıcılarını çekerek edilmelidir.

Ben araçları üreten PHP çözümleyici hiç kullanmamış, ama onlar dokümanlar hafif bir taramadan sonra tamam bakmak. LexerGenerator ve ParserGenerator göz atın. LexerGenerator bir (bu durumda, CSS) dilinde belirteçleri farklı anlatan düzenli ifadeler bir demet almak ve bireysel simgeleri tanır bazı kod tükürmek olacaktır. ParserGenerator, ne diğer şeylerden oluşur bir dilde ne şeyler açıklamasını bir dilbilgisi almak ve bir ayrıştırıcı, jeton bir demet alır ve sonra da bir sözdizimi ağacı (veri yapısı döndürür kodu tükürmek olacaktır.

Do not use your own regex for parsing CSS. Why reinvent the wheel while there is code waiting for you, ready to use ve (hopefully) bug-free?

Sizin için CSS ayrıştırmak iki genellikle mevcut sınıf vardır:

Pear.php.net at HTML_CSS PEAR paketi

ve

PHPCLasses de CSS Ayrıştırıcı sınıfı:

http://www.phpclasses.org/browse/package/1289.html

Özellikle tek regex - Ben CSS ayrıştırmak için regex bulunuyor kullanarak karşı tavsiye ederim!

Eğer regex yıllarda ayrıştırma yapmakta ısrar ederse, mantıklı bölüme o kadar bölünmüş - sonra başka bir color:rgb(1,2,3); niteliklerini ayrıştırmak için, tüm body{..} blokları bölünmüş bir regex kullanabilirsiniz.

Aslında (düzenli ifadeler öğrenmeye çalışıyorum değil) "yararlı" bir şeyler yazmak için çalışıyorsanız, önceden yazılmış bir CSS çözümleyici arayın.

Ben çok iyi iş gibi görünüyor this cssparser.php hangi bulundu:

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

.. Hangi aşağıdaki çıktılar:

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

Ayrıştırıcı oldukça basittir, bu yüzden ne yaptığını çalışmak kolay olmalıdır. Oh, ben okudum satırları kaldırmak zorunda if($this->html) {$this->Add("VAR", "");} (o sol bir hata ayıklama bir şey gibi görünüyor)

Ben yukarıdaki değişiklikleri, komut here aynalı ettik

Ben aşağıda regex kullanıyorum ve oldukça çok çalışmaları ... Tabii bu soruya şimdi eski ve ben size çabalarını terk ettik görmek ... ama durumda başkası üzerinde çalışan:

(?<selector>(?:(?:[^,{]+),?)*?)\{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?\}

(Hafta güvenli olması için önce CSS /* comments */ tüm kaldırmak)

Ben kolayca CSS ayrıştırır kodu bir parça yazdı. Yapmanız gereken tek şey gerçekten patlar bir çift yapmaktır ... $ css değişkeni CSS bir dizedir. Yapmanız gereken tek şey, tam çözümlü CSS güzel bir dizi, almak için bir print_r($css) yapmaktır.

$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];
        }
    }               
}

Bu verir:

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

Bu deneyin

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";