【问题标题】:str_replace a CSS property based upon a CSS commentstr_replace 基于 CSS 注释的 CSS 属性
【发布时间】:2011-12-18 13:51:03
【问题描述】:

我正在构建一个“主题构建器”,它将动态编辑 CSS 文件。我认为使用 PHP 将是最简单的选择(愿意考虑替代方法)。

我的 CSS 文件在每个属性之后都包含 cmets,如下所示:

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

是否可以使用替换函数来搜索该注释并仅替换它之前的代码?用户可能希望在完成主题构建后返回并再次更改某些内容,因此评论必须始终保留。

谢谢

【问题讨论】:

  • 您遇到了哪个具体问题?只需在行尾再次替换注释即可。
  • 啊,我明白了。在这种情况下,我将如何搜索评论,然后替换整行?
  • 预期输出是什么?第一行不明确,因为 bgColor 属性转换为 background-color
  • 为什么不将主题存储为带有php变量的模板作为替换点,然后在需要时设置变量并渲染输出?
  • 主题显示在不同页面的 iframe 中,因此 CSS 文件必须有效。这就是为什么我想要属性之后的 CSS cmets。 CSS 中的相同属性也可能被多次编辑,因此必须始终保留注释,以便 php 替换函数可以找到一些东西是否有意义?

标签: php javascript css ajax str-replace


【解决方案1】:

只要您遵循在行尾有 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'
;

这是带有 cmets 的正则表达式模式,可通过 x-修饰符实现。只是为了让你更容易理解。

一个重要的点是用于多行模式的m-修饰符。该模式应该适用于每一行,因此它包含在^(开始)和$(结束)中,这将在多行模式下匹配行的开头和结尾。

当您进行替换操作时,第 2 组将被替换,第 1 组和第 3 组将被保留。完成后,结果仍将包含变量名。

然后通过使用sprintfpreg_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&amp;$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;

【讨论】:

    【解决方案2】:

    您是在页面加载时生成 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);

    【讨论】:

    • 我有一个带有表单和 iframe 的页面。 iframe 正在加载主题的预览。当用户更新表单(例如 - 更改背景颜色字段)时,我希望它在 CSS 文件上执行 PHP 替换功能。由于该字段可能被多次编辑,CSS 注释必须保留,以便每次替换函数都可以引用它。不确定这是否有意义,但希望如此。
    【解决方案3】:

    几年前做过与此非常相似的事情,但我的做法是在加载时在 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);
    }   
    

    然后以与普通样式表相同的方式包含文件...

    如果您将所有变量设置为与示例中相同的名称...它将按照您希望的方式工作,而无需更改任何代码以适应其他做事方式:)

    如果您需要任何帮助,请告诉我:)

    祝你好运:)

    爱所有人:)

    【讨论】:

    • 在这种情况下,我宁愿使用 echo 将 CSS 文件编写为 PHP 文件,其中应输出用户变量。与常规 HTML 相同,只是内容类型不同 :)
    • 确实如此...与其添加小功能来调整已编写的具有 cmets 的 CSS 文件...可以将 CSS 文件重写为 PHP 文件,更改内容类型和位置您有需要更改的项目而不是 cmets 有变量...根据变量是否存在添加回声...例如... echo(isSet($textColor) ? $textColor : "#fff; ");好点 Svish :)
    猜你喜欢
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2012-12-05
    • 1970-01-01
    相关资源
    最近更新 更多