I am working on creating Web Components and I need a Regular Expression that captures instances of string interpolation in a template sting.
For example with the following string:
<img src="${this.image}"/><h5>${this.title}</h5><p>${this.description}</p>
The instances of string interpolation are inside ${}
and can be captured with: (this(\.\w ))
.
But I do not want to capture the first instance because it is inside an attribute.
I have tried the expression ((?<!". )this(\.\w ) (?!. "))
which works with a multiline string (each tag on own line) but now on a single line.
Here is my RegExr demo.
Perhaps someone with more exp in RegEx can help me out.
CodePudding user response:
I think this should work for you:
[^"]\$\{(this\.\w )
This will only take interpolations that are not preceded by "
CodePudding user response:
Use the following regex:
[^="]{2}\${(\S ?)}
- Attributes always will have a
=
and their value will be in quotes. So[^="]{2}
ensures that we match the two characters that are anything but=
and"
. (\S ?)
then lazily captures the required data in a capturing group.
CodePudding user response:
You can use a negative lookbehind to account for a quoted attribute: ?<!=["'])\$\{this(?:\.\w ) \}
. This will exclude the src="${this.image}"
in your example, but you'll get a false positive for HTML text, such as <p>Quote: "${this.quote}"</p>
You can use a negative lookbehind to account for a quoted attribute in an HTML tag: (?<!<\w (\w =["'][^"']*["'] )*\w =["'])\$\{this(?:\.\w ) \}
.
Here is an example with both regexes:
const regex1 = /(?<!["'])\$\{this(?:\.\w ) \}/g;
const regex2 = /(?<!<\w (\w =["'][^"']*["'] )*\w =["'])\$\{this(?:\.\w ) \}/g;
[
'<img src="${this.image}"/><h5>${this.title}</h5><p>${this.description}</p><p>Quote: "${this.quote}"</p>',
'<img foo="bar" src="${this.image}"/><h5>${this.title}</h5><p>${this.description}</p><p>Quote: "${this.quote}"</p>'
].forEach(str => {
console.log(str);
console.log('- regex1:', str.match(regex1));
console.log('- regex2:', str.match(regex2));
});
Explanation of regex2
:
(?<!
-- negative lookbehind start<\w
-- start of HTML tag and space<img
(\w =["'][^"']*["'] )*
-- 0 attributes of formattr="value"
, with trailing space\w =["']
-- attribute start, such assrc="
orsrc='
)
-- negative lookbehind end\$\{this
-- literal${this
(?:\.\w )
-- non-capture group for 1 patterns of.something
\}
-- literal}
Note: If your regex engine does not support negative lookbehind (notably Safari) you can change that to a capture group, and restore it with a .replace()