2

I've been trying to follow this SO answer to try and write some regex to do a pattern replace with Grunt. My regex understanding is very basic so I'm pretty lost.

Matching

.selector {
   background: url('../img/some.filename.png') no-repeat;
}

Output

.selector {
   background: url(<%= asset_path 'some.filename.png' %>) no-repeat;
}

I understand something like /url\(.*?g'\)/ig will match the url() tag but I'm not sure how to isolate the filename from within that. Using the Grunt string-replace task to run the replace.

Any pointers?

2 Answers 2

1

I have conjured a beast of a regex that I believe does the job. It requires a positive lookbehind and a positive lookahead which I don't know if Grunt supports since I don't know what that is. I'm going to assume it does, otherwise I don't think it's possible without the lookaround.

I tested this regex using C#, so here it is!

Regex:

(?<=url\s*\('([\w\._-]+/)*)([\w\._-]+)(?='\))

Test String:

url ('fruit-veggie/apple_orange-pie/this.is-my_file.png')

I will break this down as it befuzzles even me. This is composed of 3 major parts.

Positive lookbehind:

(?<=url\s*\('([\w\._-]+/)*)
  1. The (?<=) indicates whatever comes between the = and ) has to be part of the pattern that follows, but it will not be part of the match.
  2. url\s*\(' will match url (' with or without spaces.
  3. ([\w\._-]+/)* will match any string that contains at least one word character, dot, underscore, or dash, followed by a forward slash. This will consume one folder path. The * at the end will make it consume any number of folders because you might not have a folder to begin with.

Actual file name:

([\w\._-]+)

This is identical to the folder pattern except without the forward slash at the end. This will match files without extensions.

Positive lookahead:

(?='\))
  1. (?=) is the same as the positive lookbehind, except this is a lookahead which will check what comes after the pattern that precedes it.

  2. '\) simply checks that the entire string is followed by a quote and a closing bracket.

For the folder/file name pattern, you will have to tweak it based on what characters would be valid in them. So if for whatever crazy reason they can contain a #, you will have to modify those portions of the regex to include that character.

Hopefully Grunt supports this regex, otherwise I will have wasted my time. But this was a fun challenge regardless!

Update

It seems JavaScript doesn't support lookbehinds. If what you're doing is specific to your current project only, why don't you try using two regex instead of one?

function GetFile (s) {
    s = s.replace (/url\s*\('([\w\._-]+\/)*/g, '');
    return s.match (/[\w\._-]+(?='\))/)[0];
}

var s = "url ('fruit-veggie/apple_orange-pie/this.is-my_file.png')";
console.log (GetFile (s));

This will erase everything up to but not including the first character of the file name. Then it returns the file name without the end quote and bracket, because JavaScript supports lookaheads.

Sign up to request clarification or add additional context in comments.

1 Comment

This is incredible, thanks for working out a solution. I've been trying to get it to work, Grunt just uses JavaScript to interpret the Regex. I keep getting errors about invalid characters in the positive lookbehind - put it into a regex tester which is showing it as well. Any ideas?
1

You can use something like this :

(?:url\((.*?)\))

Demo

Explanation :

enter image description here

In javascript you can give :

var s="url('../img/some.filename.png')";
var ss= /(?:url\((.*?)\))/ ;   
console.log(s.match(ss)[0]);

2 Comments

Can the match just return the filename instead of the whole path?
I just tested this and it appears to return the entire url property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.