13

I have a string in this form:

url("http://www.example.com/imgs/backgrounds/bg80.jpg") repeat scroll 10% 0% transparent

This is from a CSS styling for a certain element that at the moment isn't visible on the page. What I need to do is preload that background image, but to do this I need it's URL, and I'm trying to write a regular expression find it.

I know the http://www.example.com/imgs/backgrounds/ part remains constant, the only thing changing is the image name itself, which can end with either .jpg or .png.

This was one attempt:

(http:\/\/www.example.com\/imgs\/backgrounds\/)[\w\.\-]*

The problem with this being that only the http://www.example.com/imgs/backgrounds/ part was being picked up. So I tried this, but this doesn't work at all!

(http:\/\/www.example.com\/imgs\/backgrounds\/)[\w\.\-]*(.jpg|.png)

What am I doing wrong? Thank you for any help!

Sean Bone
  • 3,368
  • 7
  • 31
  • 47

5 Answers5

29

A background url can have ' or " or none around the url inside the parenthesis

Valid urls

  • url("http://www.example.com/imgs/backgrounds/bg80.jpg")
  • url('http://www.example.com/imgs/backgrounds/bg80.jpg')
  • url(http://www.example.com/imgs/backgrounds/bg80.jpg)

So for a generic solution you could use

var background = 'url("http://www.example.com/imgs/backgrounds/bg80.jpg") repeat scroll 10% 0% transparent',
    reg = /(?:\(['"]?)(.*?)(?:['"]?\))/,
    extracterUrl = reg.exec(background)[1];
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • 2
    This should be the accepted answer; it's a single regexp that extracts urls from all possible declaration formats, without the need to `.replace()` anything. – Christophe Marois Jun 20 '14 at 15:05
  • 2
    Shouldn't the regex contain the "`url`" word as well? – Udo G Apr 14 '16 at 14:58
  • @UdoG no because we are trying to extract the actual URL string. And since there are very specific rules about how the properties of the `background` property are constructed there can be nothing else inside parenthesis (*which is what we use to identify the url*) – Gabriele Petrioli Apr 14 '16 at 17:30
  • What's the pipe character doing in the character enumeration? That's wrong, isn't it? – John May 05 '16 at 22:57
  • Why is it wrong to include the word "url"? It obviously wouldn't affect what the group matches on. – John May 05 '16 at 23:00
  • @John you are right about the pipe. I must have been trying without the `[]` and it was left there. About the "**url**", it *could* be in there but it would offer no extra assistance so it is not required. – Gabriele Petrioli May 05 '16 at 23:05
  • This wouldn't work if you have gradients or rgba(...) that also use parenthesis – Benjamin Intal Aug 31 '16 at 10:21
  • backgroundImage can contain multiple image urls, if transparent layers or as a fallback on loading error. `'url("http://foo/bar.png"), url("http://bar/foo.png")'` – holmberd Oct 29 '17 at 19:38
  • The answer fails if a URL contains parentheses, e.g., `url("http://example.com/so)me(img).png")`. I don't know what a regex solution could be for a random string, but you could assign your style to an Element and extract background-image with `getComputedStyle` - at least FF converts it to a nice string between 2 double-quotes. – Jonh Smith Nov 30 '21 at 04:09
17

Just capture anything between ( and )

var url = str.match(/\((.*?)\)/)[1].replace(/('|")/g,'');

var image = new Image();
image.src = url;

FIDDLE

adeneo
  • 312,895
  • 29
  • 395
  • 388
4

I feel like Gaby's answer is almost correct, but according to this answer, unquoted CSS URLs can include escaped characters (ex: background-image: url(http://foobar.com?\'\() is a valid way to load a background image with the url http://foobar.com?'). A more accurate expression for capturing all URLs in a stylesheet (tests here):

/[:,\s]\s*url\s*\(\s*(?:'(\S*?)'|"(\S*?)"|((?:\\\s|\\\)|\\\"|\\\'|\S)*?))\s*\)/gi

var urlMatchingRegex = /[:,\s]\s*url\s*\(\s*(?:'(\S*?)'|"(\S*?)"|((?:\\\s|\\\)|\\\"|\\\'|\S)*?))\s*\)/gi;

myStylesheetString.replace(urlMatchingRegex, function(fullMatch, url) { 
  //Replacement handler 
});
Community
  • 1
  • 1
AlexZ
  • 11,515
  • 3
  • 28
  • 42
1

I just do it now and I get to this page so I think so my pattern its simply and absolutely:

/url(?:\([\'"\s]?)((?!data|http|\/\/)(\.\.?\/|\/))(.*?)(?:[\'"\s]?\))/g

Moshe Harush
  • 671
  • 6
  • 20
0

So here's a cleaned up version that only focuses on images & converts found images relative paths to absolute. This way you can preload easily. This code creates an array with original URL and absolute URL. You can simply loop through the result and preload the absolute URL images

var myString = " \
    background: url(../images/magnifier-ico.png) no-repeat left center; \
    background: url(../../images/globe-ico.png) no-repeat; \
    background: url(../images/magnifier-ico.png) no-repeat left center; \
";

var myRegexp = /(?:\(['|"]?)(.*?\.(png|jpg|gif|jpeg|tiff){1})(?:['|"]?\))/gi;

// Set location of CSS file being read
var cssFile = "/css/mobile/style.css";

// Figure out depth of the css file in relation to root
var cssPath = cssFile.split("/").filter(function(item){return item.length>0;});
var depth = (cssPath.length);

// Array to store found images
var images = [];

// Start search
var match = myRegexp.exec(myString);
while (match) {
  // get image
  var foundImage = match[1];

  // Look for next one
  match = myRegexp.exec(myString);

  // Convert relative path to absolute
  var relativeDepth = 0;
  var pathRegexp = /\.\.\//gi;
  var pathMatch = pathRegexp.exec(foundImage);
  while(pathMatch){
    relativeDepth++;
    pathMatch = pathRegexp.exec(foundImage);
  }
  // Strip the relativity
  var pathlessImage = foundImage.split("../").join("");
  // Now to the final conversion
  var absolute = "";
  for(var i=0;i<depth-relativeDepth-1;i++)
    // Reconstruct it all back
    absolute += "/" + cssPath[i];

  // Now add image name
  absolute += "/" + pathlessImage;

  // Store final cleaned up product
  images.push({original:foundImage,absolute:absolute});
}

console.log(images);

Here's working JSbin http://jsbin.com/nalimaruvu/2/

denisbetsi
  • 85
  • 2
  • 5