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

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?

  • 写回答

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}";
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!