Vojthas
Vojthas

Reputation: 53

Convert regexp from php to javascript (lookback assertion)

I have this regexp to replace embedded RGB colors {rrggbb} (always exactly 6 characters enclosed in curly brackets) into html span tags: {([a-fA-F0-9]+)}((?>[^{]*{?(?!(?1)}))*)

It was used like this:

preg_replace('~{([a-fA-F0-9]+)}((?>[^{]*{?(?!(?1)}))*)~', '<span style="color: #$1">$2</span>', $text);

It worked well with preg_replace in php, but when trying to use it in javascript I'm getting a syntax error (? The preceding token is not quantifiable)

How can I make it work in javascript?

Note I have another regexp: {([a-fA-F0-9]{6})\}([^\{]+) which works, however if I do something like this: {ff0000}red text {some text that isn't a color} {00ff00}blue text I'm getting an output of: <span style="color: #ff0000">red text </span>{some text that isn't a color} <span style="color: #00ff00">blue text</span>, note that {some text that isn't a color} isn't wrapped in any span tag, while it still should be in the previous tag. I dont know how to fix it though.

Upvotes: 1

Views: 31

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627468

JS regexp does not support subroutines, but you may define a block as a variable, and build a pattern dynamically. Also, the (?>[^{]*{?(?!(?1)}))* part is too cryptic (and contains an atomic group (?>...) that is not supported by JS RegExp, either), and what it does is just matches any 0+ chars other than { that is not followed with hex chars up to the closing } and so on up to the RGB pattern (a kind of an unroll-the-loop principle variation).

JS equivalent is

var s = "{ff0000}red text {some text that isn't a color} {00ff00}blue text";
var xdigit = "[a-fA-F0-9]+";
var result = s.replace(new RegExp("{("+xdigit+")}([^{]*(?:{(?!"+xdigit+"})[^{]*)*)", "g"), '<span style="color: #$1">$2</span>');
console.log(result);

The pattern used is

/{([a-fA-F0-9]+)}([^{]*(?:{(?![a-fA-F0-9]+})[^{]*)*)/g

See the JS regex demo here.

  • { - a { char
  • ([a-fA-F0-9]+) - Group 1: one or more (use {6} to only match 6) hex chars
  • } - a } char
  • ([^{]*(?:{(?![a-fA-F0-9]+})[^{]*)*) - Group 2:
    • [^{]* - any 0+ chars other than {
    • (?:{(?![a-fA-F0-9]+})[^{]*)* - zero or more occurrences of the following sequence of patterns:
      • { - a { that is....
      • (?![a-fA-F0-9]+}) - not followed with 1+ hex chars and then a }
      • [^{]* - any 0+ chars other than {

Upvotes: 1

Related Questions