preg_replace()正则表达式匹配CSS文件中的相对url()路径

时间:2012-03-21 03:52:38

标签: php regex preg-replace

我正在组合一些CSS文件并将它们写入单独目录中的文件。我正在尝试替换相对url()值以使用新文件位置,忽略任何绝对URL。这是一些示例CSS:

#TEST {
    background:url(test.jpg);
    background:url( 'test.jpg' );
    background:url("test.jpg"  );
    background:url(http://example.com/test.jpg);
    background:url('https://example.com/test.jpg');
    background:url("http://example.com/test.jpg");
    background:url( '//example.com/test.jpg' );
    background:url( "//example.com/test.jpg" );
    background:url(//example.com/test.jpg);
}

任何不以http://https:////开头的内容都应该在$path之前注入(只有前3个匹配)。

期望的输出:

#TEST {
    background:url(/themes/default/css/test.jpg);
    background:url( '/themes/default/css/test.jpg' );
    background:url("/themes/default/css/test.jpg"  );
    background:url(http://example.com/test.jpg);
    background:url('https://example.com/test.jpg');
    background:url("http://example.com/test.jpg");
    background:url( '//example.com/test.jpg' );
    background:url( "//example.com/test.jpg" );
    background:url(//example.com/test.jpg);
}

但是,this code与之相反:

$path = '/themes/default/css/';
$search = '#url\(\s*([\'"]?)((http(s)?:)?//)#';
$replace = "url($1{$path}$2";
$css = preg_replace($search, $replace, $css);

我知道您可以使用类似!^(http) 来匹配以http开头的字符串,但我尝试过的所有内容都失败了(我= =正则表达式)。我一直在使用online regex tester来解决这个问题,但我确实陷入困境。

这可能不是我用来解决实际问题的方法(确保路径在编译的CSS中工作)但是任何人都可以帮我修复这个正则表达式问题,或者有更好的解决方案吗?

4 个答案:

答案 0 :(得分:11)

你几乎就在那里 - 你所追求的“以不匹配的字符串开头”被称为“负向前瞻”并且看起来像(?!http)

因此,对于url\(未跟\s*['"]?(https?:)?//,您可以执行以下操作:

url\((?!\s*['"]?(http(s)?:)?//)

(我保留了(s)捕获组,如果你想抓住它,但你不需要(s)周围的那些括号; s?与{{(s)?相同1}}如果你不关心捕获)。

在行动here中查看。

编辑:

由于你想把$ path放在引号后面(如果有的话),我把正则表达式修改为:

url\((?!\s*['"]?(?:https?:)?//)\s*(['"])?

即。删除了我不关心的所有捕获括号,并添加了\s*(['"])?来捕获它是什么类型的引用。

认为它在codepad here中,但以防万一,这是代码:

$path = '/themes/default/css/';
$search = '#url\((?!\s*[\'"]?(?:https?:)?//)\s*([\'"])?#';
$replace = "url($1{$path}";

答案 1 :(得分:4)

此pregmatch与所选答案一样好,但也支持原始数据

'#url\((?!\s*([\'"]?(((?:https?:)?//)|(?:data\:?:))))\s*([\'"])?#'

以下是该长正则表达式的构建块

$absoluteUrl = '((?:https?:)?//)';
$rawData = '(?:data\:?:)';
$relativeUrl = '\s*([\'"]?((' . $absoluteUrl . ')|(' . $rawData . ')))';
$search = '#url\((?!' . $relativeUrl . ')\s*([\'"])?#';
$replace = "url($6{$path}";
echo preg_replace($search, $replace, $css);

完整示例

http://codepad.org/NDoya4NC

答案 2 :(得分:1)

我使用以下模式(基于此处的其他答案):

url\s*\(\s*[\'"]?(?!(((?:https?:)?\/\/)|(?:data\:?:)))([^\'"\)]+)[\'"]?\s*\)

让它运行的PHP是:

$path = '/themes/default/css/';
$search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%';
$replace = 'url("' . $path  . '/$3")';
$css = preg_replace($search, $replace, $css);
  • 允许括号周围的空格
  • 支持http,https,数据和#34; //"
  • 的负面预测
  • 在替换资产周围插入引号

此处提供测试:https://regex101.com/r/zT2gM9/1

答案 3 :(得分:0)

让它发挥作用:

$sBaseUrl = 'http://example.com/';
$sCss = preg_replace_callback(
    '|url\s*\(\s*[\'"]?([^\'"\)]+)[\'"]\s*\)|',
    function($aMatches) use ($sBaseUrl) {
        return 'url("'. $sBaseUrl . trim($aMatches[1]). '")';
    },
    $sCss
);
print $sCss;