3

Using JavaScript I need to check a string for the first instance of a given pattern and return everything after, and including, the pattern. See example below for a typical string, pattern and desired result.

The main problem I am having is that the pattern will almost certainly contain special characters such as parentheses. I cannot alter the pattern manually to escape those special characters. Unless I am able to do that using replace first?

e.g. result = string.match(pattern.replace(special with escaped))

I'm not sure if anything like that is even possible. Regex always gives me a headache and I would appreciate any pointers in the right, or alternative, direction.

Background

I am trying to do some complex mixins for LESS. So I am restricted to single line JavaScript by escaping with the back-tick. See here for information regarding using JavaSCript in LESS. I was hoping to use the new variadic argument support to get multiple color-stops. e.g. .radial-gradient(@shape, @position, @colorStops...) However LESS only gives you the full range of arguments passed when you use @arguments. So I am hoping to use regex to use @arguments for the string and @colorStop for the pattern and return everything after, and including, the first color-stop. LESS returns the first color-stop variable when using @colorStop. The general concept was taken from here)

For Example:

String: circle 0% 50% rgba(96, 16, 48, 0) 9px #661133 10px rgba(96, 16, 48, 0) 11px

Pattern: rgba(96, 16, 48, 0) 9px

Result: rgba(96, 16, 48, 0) 9px #661133 10px rgba(96, 16, 48, 0) 11px

Jeroen Heier
  • 3,520
  • 15
  • 31
  • 32
runey71
  • 168
  • 1
  • 2
  • 12

2 Answers2

3

"I cannot alter the pattern manually to escape those special characters. Unless I am able to do that using .replace first?"

Yes you can. Given a variable pattern that is a string containing your regex pattern, then:

pattern = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');

...will escape all of the characters that have special meaning in a regex, and put the result back in the same variable. Of course that only works if every character in your pattern is to be taken as a literal character to match.

"I need to check a string for the first instance of a given pattern and return everything after, and including, the pattern"

I'd simply append .* to the end of the pattern, so then it will match the specified bit followed by all of the following characters. That is, if a regex /abc/ matches the first instance of "abc" then the regex /abc.*/ will match "abc" plus every character following. (In a regex, . matches any character, and * matches the previous bit zero or more times, by default doing a "greedy" match.)

Putting this together:

function matchToEnd(pattern, str) {
    var re = new RegExp(pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + ".*"),
        result = str.match(re);
    if (result)
       return result[0];
    else {
       // didn't match, return default value of your choice, e.g.:
       return null;
    }
}

var result = matchToEnd("rgba(96, 16, 48, 0) 9px",
                        "rgba(96, 16, 48, 0) 9px #661133 10px rgba(96, 16, 48, 0) 11px");

Demo: http://jsfiddle.net/JVdnz/

Note though that going back to the assumption I had to make earlier that your regex pattern didn't contain any characters that have special meaning in a regex, if that is the case then you don't need regex to do this task, you can just use the .indexOf() method in combination with the .substr() method:

var i = str.indexOf(pattern);  // find index of first instance of pattern
if (i != -1)
   return str.substr(i);       // return from that index to end of string

Here's a demo similar to previous demo but with .indexOf() instead of regex: http://jsfiddle.net/JVdnz/1/

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • Thank you for such a detailed response and the examples via jsfiddle. Both options look promising. I'm currently trying to adapt it to work within the limitations of the LESS compiler. Almost there :) I'll mark it as the correct answer as soon as I do get it working within LESS. – runey71 Sep 14 '12 at 00:27
2

If your pattern doesn not need to use any regex features, and if you only need to replace the first occurrance if it, then you can just pass a string as the pattern to the replace method.

Otherwise (if you need regex features or need to replace all occurences of the pattern) then you can create a function to escape the special characters in your string and dynamically generate a regex object.

Community
  • 1
  • 1
hugomg
  • 68,213
  • 24
  • 160
  • 246
  • I actually need to return everything after, and including, the pattern being matched. So I'm not sure how passing the pattern as a string to the replace method can help me achieve that. Perhaps I'm misunderstanding? PS: Checking out the link you provided. – runey71 Sep 13 '12 at 02:43