preg_replace()regex来匹配CSS文件中的相对url()路径


preg_replace() regex to match relative url() paths in CSS files

我正在组合一些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);
}

然而,这个代码与之相反:

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

我知道您可以使用类似!^(http)的东西来而不是匹配以http开头的字符串,但我尝试的所有操作都失败了(我在regex方面做得很糟糕)。我一直在使用在线regex测试仪来解决这个问题,但我真的被卡住了。

这可能不是我用来解决真正问题的方法(确保路径在编译的CSS中工作),但有人能帮助我解决这个regex问题,或者有更好的解决方案吗?

你就快到了-你追求的是"不匹配以"开头的字符串;被称为";负前瞻";并且看起来像CCD_ 8。

因此,对于后面没有's*['"]?(https?:)?//url'(,您可以执行:

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

(我把(s)捕获组放在那里,以备你想捕获它,但你不需要(s)周围的括号;如果你不在乎捕获,s?(s)?是一样的)。

请在此处查看它的实际操作。

编辑:

由于您想将$path放在引号(如果有的话)之后,我将regex修改为:

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

即删除了我不关心的所有捕获括号,并添加了一个's*(['"])?来捕获它是什么样的报价。

认为它在这里的代码板中,但以防万一,这里是代码:

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

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

'#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

我通过以下模式(基于此处的其他答案)得到了这个结果:

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、data、"//"的负面前瞻
  • 在替换的资产周围插入引号

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

开始工作:

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