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条)

报告相同问题?

悬赏问题

  • ¥15 openwrt双栈NAT
  • ¥15 部分网页页面无法显示!
  • ¥15 怎样解决power bi 中设置管理聚合,详细信息表和详细信息列显示灰色,而不能选择相应的内容呢?
  • ¥15 QTOF MSE数据分析
  • ¥15 平板录音机录音问题解决
  • ¥15 请问维特智能的安卓APP在手机上存储传感器数据后,如何找到它的存储路径?
  • ¥15 (SQL语句|查询结果翻了4倍)
  • ¥15 Odoo17操作下面代码的模块时出现没有'读取'来访问
  • ¥50 .net core 并发调用接口问题
  • ¥15 网上各种方法试过了,pip还是无法使用