doujiang1913
2012-03-21 03:52
浏览 117
已采纳

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

I'm combining some CSS files and writing them to a file in a separate directory. I'm trying to replace the relative url() values to work with the new file location, ignoring any absolute URLs. Here's some sample 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);
}

Anything that doesn't start with http://, https:// or // should get $path injected before it (only the first 3 should match).

Desired output:

#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);
}

However, this code is matching the opposite:

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

I know you can use something like !^(http) to not match strings that start with http, but everything I've tried has failed (me === bad at regex). I've been using an online regex tester to figure this out but am truly stuck.

This might not be what I use to solve the real problem (making sure paths work in compiled CSS) but can anyone help me fix this regex problem, or have a better solution?

图片转代码服务由CSDN问答提供 功能建议

我正在组合一些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'); 
后台:url(“http://example.com/test.jpg”); 
后台:url('// example@test.jpg'); \  n 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); 
后台:url('https://example.com/test.jpg'); 
后台:url(“http://example.com/test.jpg”); 
后台:  url('// example = test.jpg'); 
后台:url(“// example.com/test.jpg”); 
后台: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上不好)。 我一直在使用在线正则表达式测试仪来解决这个问题,但我确实陷入困境。

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

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

4条回答 默认 最新

  • dongtongjian3127 2012-03-21 04:01
    已采纳

    You're almost there - what you're after for the "not matching strings starting with" is called a "negative lookahead" and looks like (?!http).

    So for url\( not followed by \s*['"]?(https?:)?//, you do:

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

    (I kept that (s) capturing group in there incase you wanted to capture it, but you don't need those brackets around the (s); s? is the same as (s)? if you don't care about capturing).

    See it in action here.

    Edit:

    Since you want to put the $path after the quote mark (if any), I modified the regex to:

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

    i.e. removed all capturing brackets I don't care about, and added a \s*(['"])? to capture what kind of quote it is.

    I think it is in codepad here, but just in case, here is the code:

    $path = '/themes/default/css/';
    $search = '#url\((?!\s*[\'"]?(?:https?:)?//)\s*([\'"])?#';
    $replace = "url($1{$path}";
    
    点赞 打赏 评论
  • dounue6984 2014-08-21 07:46

    Got it to work:

    $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;
    
    点赞 打赏 评论
  • duandu8707 2014-11-15 22:09

    This pregmatch is as good as selected answer, but also supports raw data

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

    Here are the building blocks of that long regular expression

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

    Full example

    http://codepad.org/NDoya4NC

    点赞 打赏 评论
  • dsa5233 2016-04-28 05:40

    I got this working with the following pattern (based on other answers here):

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

    The PHP to get it to run is:

    $path = '/themes/default/css/';
    $search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%';
    $replace = 'url("' . $path  . '/$3")';
    $css = preg_replace($search, $replace, $css);
    
    • allows spaces around the brackets
    • supports the negative lookahead for http, https, data, "//"
    • inserts quotes around the replaced asset

    Test available here: https://regex101.com/r/zT2gM9/1

    点赞 打赏 评论

相关推荐 更多相似问题