Todd Sharp and I were talking today about finding URLs within CSS. Specifically - things in the format of url(...). For example (and yes, I know this is a bad CSS example since it repeats the same ID, but I built it up with cut and paste):

#id{ background-image: url('foo.jpg'); }

#id{ background-image: url('goo.jpg'); }

#id{ background-image: url('doo.jpg'); }

Todd had the following regex courtesy of a blog post by Ben Nadel:


And while this can return all the instances, it also includes the wrapping url(). I don't believe what Todd wanted could be done in one function call, but there are a few ways we could do it in a loop. Here is what i came up with.

<cfsavecontent variable="s"> #id{ background-image: url('foo.jpg'); }

#id{ background-image: url('goo.jpg'); }

#id{ background-image: url('doo.jpg'); }


<cfset matches = reFind("url(([^)]+))",s, 1, true)> <cfloop condition="matches.pos[1] gt 1"> <cfset match = mid(s, matches.pos[2], matches.len[2])> <cfset match = rereplace(match,"['""]", "", "all")> <cfoutput> match was #match#<p> </cfoutput> <cfset matches = reFind("url(([^)]+))",s, matches.pos[1]+matches.len[1], true)> </cfloop>

Basically I just use a conditioned loop and reFind. Note the use of the fourth argument to ensure I get subexpressions back. It may be hard to see, but I modified Ben's regex to add an additional ( and ) around the 'inner' portion of the match. The result of my reFind call will be both the entire match as well as the inner match. I do one more quick regex replacement to get rid of the single or double quotes (and I'm pretty sure this could be done in the original regex instead, but it's one more line so I won't be losing any sleep over it), and then I output the result. Given the sample string above, my results are:

match was foo.jpg
match was goo.jpg
match was doo.jpg