Preg_replace () regex to match relative url () in CSS files

I merge some CSS files and write them to a file in a separate directory. I am trying to replace relative url() values ​​to work with a new file location, ignoring absolute URLs. Here is a CSS example:

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

Everything that does not start with http:// , https:// or // should get $path in front of it (only the first 3 must match).

Desired conclusion:

 #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 corresponds to the opposite:

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

I know that you can use something like !^(http) to not match lines starting with http , but everything I tried failed (I === bad in regex). I use the online regexp tester to figure this out, but really stuck.

This may not be what I'm using to solve the real problem (make sure the paths work in compiled CSS), but can someone help me fix this problem with regex or have a better solution?

+7
source share
4 answers

You are almost there - what you need for "inappropriate lines starting with" is called a "negative look" and looks like (?!http) .

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

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

(I saved the capture group (s) where you want to capture it, but you don't need those brackets around (s) ; s? matches (s)? unless you care about capture).

See in action here .

Edit:

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

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

i.e. deleted all the capturing brackets that I don’t need and added \s*(['"])? to fix what the quote is.

I think this is in the codec here , but just in case, here is the code:

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

This pregmatch is as good as the selected answer, but also supports the source data.

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

Here are the string blocks of this 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

+4
source

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

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

PHP to run it:

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

The test is available here: https://regex101.com/r/zT2gM9/1

+1
source

I tried 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; 
0
source

All Articles