1

I'm struggling to get a string replaced in Javascript by a regex matching pattern. I want to replace all matches of {{$myparam}} to be surrounded by a span tag. This works (see code below). But I want to prevent replacements when a match is preceded by href=".

Example: href="{{$myparam}} must NOT be replaced. {{$myparam}} MUST be replaced. myparam can be any text string.

  var highlighted = html.replace(/(\{\{(.*?)\}\})/g, function highlight(x) {
       return "<span class='highlight'>" + x + "</span>";
   });

I've checked out numerous examples in other threads, but I cannot find a solution that works for my case.

nexana
  • 1,096
  • 1
  • 9
  • 18
  • 2
    I don't think regular expressions are the correct tool here, as you can't detect whether you're inside a set of quotes correctly with regular expressions. – starbeamrainbowlabs Nov 23 '17 at 15:31
  • @starbeamrainbowlabs I've changed the question to be matched when the string "is not preceded by href="" . From what I've read in other threads, this should be possible whit regex. But I can't get it to work for my case. – nexana Nov 23 '17 at 15:35
  • `/[^"]\{\{(.*?)\}\}/` this should work if your match will always be preceded by something. You could add a check for the closing qoute if you know it will be succeeded by something. – pishpish Nov 23 '17 at 15:36
  • Negative lookbehind is finding matches, not preceded by something. – Igl3 Nov 23 '17 at 15:37
  • Ah, ok. In that case you may be able to get away with a negative lookbehind. Javascript regular expressions don't support them, but that doesn't mean to say you can't replicate the functionality using other syntax... see [this SO answer](https://stackoverflow.com/a/7376612/1460422). – starbeamrainbowlabs Nov 23 '17 at 15:38
  • 1
    @Igle: Negative lookbehinds are not supported in `JavaScript`. – Jan Nov 23 '17 at 15:45

2 Answers2

1

You could use

var subject = 'href="{{$myparam}}" or any other {{$myparam}}';
var regex = /"[^"]*"|(\{\{(.*?)\}\})/g;

replaced = subject.replace(regex, function(m, group1) {
    if (typeof group1 == 'undefined') return m;
    else return "<span class='highlight'>" + group1 + "</span>";
});
alert(replaced);
# href="{{$myparam}}" or any other <span class='highlight'>{{$myparam}}</span>

See a demo on regex101.com.


The idea here is to check for
not_interesting|not_interesting_either|(very_interesting)

and check for the presence of a captured group. You can put anything not interesting to the left as in this example: "[^"]*" (that is anything between double quotes).
If you want to read more on the subject, have a look here.

Jan
  • 42,290
  • 8
  • 54
  • 79
  • Thank you, that does the trick. One question: what is the purpose of ´var match = regex.exec(subject);´ ? It seems to work without it. – nexana Nov 23 '17 at 15:47
0

This seems a bit simpler, just make the href part optional:

mystring = 'this has {{$param1}} and {{$param2}} and href="{{$param3}}" too';

console.log(mystring
 .replace(/(href=.)?\{\{([^{} ]+)\}\}/g, 
          function (match,chk,param) {
             return "undefined" !== typeof(chk)
                    ? match
                    : '<span class="highlight">' + param + '</span>';
          }));

The second argument to the callback function is the 'check' part, and the third argument is the captured parameter name. Since the check part is optional and it's fairly precise, it'll only be defined at all if it's 'href="'.

Output, with newlines added for readability:

this has <span class="highlight">$param1</span> 
and <span class="highlight">$param2</span> 
and href="{{$param3}}" too
Jeremy Jones
  • 4,561
  • 3
  • 16
  • 26