str_replace свойство CSS на основе комментария CSS - PullRequest
0 голосов
/ 18 декабря 2011

Я создаю "компоновщик тем", который будет динамически редактировать файл CSS на лету.Я подумал, что использование PHP будет самым простым вариантом (готов рассмотреть альтернативные методы).

Мой CSS-файл содержит комментарии после каждого свойства, например, так:

html,body {
    background: #fff url(../images/bg.jpg) repeat-x; /*{bgColor}*/ 
    color: #fff; /*{textColor}*/ 
}

Можно ли использовать заменуфункция, которая ищет этот комментарий и заменяет только код перед ним?Пользователь может захотеть вернуться назад после завершения создания темы и снова что-то изменить, поэтому комментарий должен оставаться всегда.

Спасибо

Ответы [ 3 ]

2 голосов
/ 19 декабря 2011

Пока вы следуете шаблону, в котором у вас есть varname в конце строки и каждая строка содержит только CSS property : value, вы можете делать это с помощью поиска и замены на основе регулярных выражений.

Если вы хотите это сделать, позаботьтесь о том, чтобы новое значение не содержало ничего нового в новой строке в смысле PCRE: \r\n|\n|\x0b|\f|\r|\x85 (не в режиме UTF-8). Если вы этого не сделаете, это сломает ваш парсер!

Для этого вы можете создать маску для шаблона, чтобы потом можно было легко вставить имя переменной позже, для этого обычно используется sprintf:

$patternMask = 
'~
   ^ # start of line

    (\s*[a-z]+:\s*)
    # Group 1: 
    #   whitespace (indentation)
    #   + CSS property and ":"
    #   + optional whitespace

    (.*?) # Group 2: CSS value (to replace)

    (\s*/\*\{%s\}\*/\s*)
    # Group 3: 
    #   whitespace (after value and before variable)
    #   + variable comment, %%s is placeholder for it\'s name

   $ # end of line

   # Pattern Modifiers:
   #   m: ^ & $ match begin/end of each line
   #   x: ignore spaces in pattern and allow comments (#)
  ~mx'
;

Это шаблон регулярного выражения с комментариями, сделанный возможным с помощью модификатора x. Тебе так легче понять.

Важным моментом является модификатор m для многострочного режима. Шаблон должен работать в каждой строке, поэтому он заключен в ^ (Begin) и $ (End), что будет соответствовать началу и концу строки в многострочном режиме.

Когда вы выполните операцию замены, группа 2 будет заменена, группа 1 и 3 будут сохранены. После этого результат все равно будет содержать имя переменной.

Фактический шаблон регулярного выражения затем строится с помощью этой маски, добавляя в нее правильно заключенное в кавычки имя переменной, используя sprintf и preg_quote:

$varName = 'bgColor';
$value = '#f00 url(../images/bg-reg.jpg) repeat-x;';

# create regex pattern based on varname
$pattern =  sprintf($patternMask, preg_quote($varName, $patternMask[0]));

$patternMask[0] равно ~, поэтому, если имя вашей переменной будет содержать ~, оно будет автоматически экранировано.

Шаблон поиска теперь завершен. Осталось только замена. Как и имя переменной, строка замены также должна быть экранирована, чтобы не разбивать ее по регулярному выражению (синтаксическая ошибка). Кроме того, как указывалось ранее, весь процесс должен позаботиться о сохранении новой строки в одной строке, в противном случае выполнение операции замены в следующий раз приведет к ее поломке. Таким образом, чтобы предотвратить это, любой символ новой строки будет заменен одним пробелом в $value, чтобы предотвратить это:

# replace characters that will break the pattern with space
$valueFiltered = str_replace(explode('|', "\r\n|\n|\x0b|\f|\r|\x85"), ' ', $value);

Тогда будут заключены в кавычки специальные символы \ и $, чтобы они не мешали шаблону замены и строилась строка замены. это делается с помощью функции addcslashes:

# escape $ characters as they have a special meaning in the replace string 
$valueEscaped = addcslashes($valueFiltered, '\$');
$replace = sprintf('${1}%s$3', $valueEscaped);

Осталось только запустить операцию замены, так что предварительно предоставив ей CSS-код:

$css = <<<CSS
html,body {
    background: #fff url(../images/bg.jpg) repeat-x; /*{bgColor}*/ 
    color: #fff; /*{textColor}*/ 
}
CSS;

и запустите замену с preg_replace:

$newCss = preg_replace($pattern, $replace, $css);

Это уже все. Из оригинального CSS:

html,body {
    background: #fff url(../images/bg.jpg) repeat-x; /*{bgColor}*/ 
    color: #fff; /*{textColor}*/ 
}

К итогу CSS:

html,body {
    background: #f00 url(../images/bg-reg.jpg) repeat-x; /*{bgColor}*/ 
    color: #fff; /*{textColor}*/ 
}

Если вы используете параметр preg_replace &$count, вы можете проверить, была ли переменная частью строки:

$newCss = preg_replace($pattern, $replace, $css, -1, $count);

$count равно 1 в данном примере.

Если вы хотите заменить несколько значений одновременно, вы можете использовать массивы как $pattern и $replace, если это полезно. $count все еще будет целым числом, поэтому может иметь ограниченное использование.

Весь код с первого взгляда:

$css = <<<CSS
html,body {
    background: #fff url(../images/bg.jpg) repeat-x; /*{bgColor}*/ 
    color: #fff; /*{textColor}*/ 
}
CSS;


$patternMask = 
'~
   ^ # start of line

    (\s*[a-z]+:\s*)
    # Group 1: 
    #   whitespace (indentation)
    #   + CSS property and ":"
    #   + optional whitespace

    (.*?) # Group 2: CSS value (to replace)

    (\s*/\*\{%s\}\*/\s*)
    # Group 3: 
    #   whitespace (after value and before variable)
    #   + variable comment, %%s is placeholder for it\'s name

   $ # end of line

   # Pattern Modifiers:
   #   m: ^ & $ match begin/end of each line
   #   x: ignore spaces in pattern and allow comments (#)
  ~mx'
;

$varName = 'bgColor';
$value = '#f00 url(../images/bg-reg.jpg) repeat-x;';

# create regex pattern based on varname
$pattern =  sprintf($patternMask, preg_quote($varName, $patternMask[0]));

# replace characters that will break the pattern with space
$valueFiltered = str_replace(explode('|', "\r\n|\n|\x0b|\f|\r|\x85"), ' ', $value);

# escape $ characters as they have a special meaning in the replace string 
$valueEscaped = addcslashes($valueFiltered, '\$');

$replace = sprintf('${1}%s$3', $valueEscaped);

$newCss = preg_replace($pattern, $replace, $css);

echo $newCss;
1 голос
/ 18 декабря 2011

Несколько лет назад сделал что-то очень похожее на это, но я сделал так, чтобы переменная сеанса с ним читалась в файле CSS (или, скорее, PHP) при загрузке.

Итак... если вы создадите php-файл, который будет действовать как ваш CSS-файл, и скопируете его в него ...

header("Content-type: text/css");
// setup replacement variables here...
// NOTE: if using the session object to start the session
// as the stylesheet is running in a seperate process as the rest of the site...

$textColor = "#ff0000";     // This is a variable that will appear in the CSS 

$fHandle = @fopen("site.css", "r");   // Change this to your CSS file...
if ($fHandle) {
    while (($line = fgets($fHandle, 4096)) !== false) {
        $variable = getTextBetween($line,"/*{","}*/");
        if ($variable != ""){
            if (isSet($$variable)){
                // we have that variable... now what to actually do with it...
                // what we are going to do is rebuild the line...
                $attribute = getTextBetween($line,0,":");
                // and thats it really...
                echo($attribute.":".$$variable.";".chr(10));   // NOTE: Double $$ to access the string as a variable :)
            } else {
                // that variable does not exist. Just output the line
                echo $line;
            }
        } else {
            // there is no variable just output the line
            echo $line;
        }
    }
    fclose($fHandle);
}

function getTextBetween($string_in,$start_in,$end_in){
    $_start = 0;
    $_end = 0;
    // calculate the start and the end points.
    if (is_string($start_in)){
        $_start = strpos($string_in,$start_in);
        if ($_start === false){
            $_start = 0;
        } else {
            $_start += strlen($start_in);
        }
    } else if (is_numeric($start_in)){
        $_start = $start_in;
    }

    if (is_string($end_in)){
        $_end = strpos($string_in,$end_in,$_start);
        if ($_end === false) $_end = 0;
    } else if (is_numeric($end_in)){
        $_end = $end_in;
    }

    $_return = substr($string_in,$_start,($_end-$_start));

    return trim($_return);
}   

Затем включите файл так же, как в обычную таблицу стилей ...

И если вы установите все свои переменные с тем же именем, что и в вашем примере ... это сработает так, как вы хотите, чтобы это работало, без необходимости изменять какой-либо код в соответствии с другими способами выполнения действий:)

Если вам нужна помощь, пожалуйста, дайте мне знать:)

Удачи:)

Любви ко всем:)

1 голос
/ 18 декабря 2011

Вы генерируете CSS при загрузке страницы, или вы регенерируете файл CSS, когда тема добавляется?

Если вы генерируете CSS при редактировании темы, вы можете сделать это;

/*bodybg*/ background: #fff url(../images/bg.jpg) repeat-x; /*/bodybg*/

Вы можете сделать что-то вроде:

$shortCode = bodybg
$cssContents = preg_replace("/(\/\*".$shortCode."\*\/).*?(\/\*\/".$shortCode."\*\/)/i",
                            "\\1 background: #F00; \\2", 
                            $cssContents);

Если вы генерируете CSS при загрузке страницы, вы можете сделать это:

background: {{bodyBgColor}} url(../images/bg.jpg) repeat-x;

$cssContents = str_replace("{{bodyBgColor}}", $color, $cssContents);

...