1

I've spent an insane amount of time trying to find the appropriate regEx to select in a string, only those elements that are enclosed by unescaped custom delimiters (with delimiters included).


My custom delimiters :

${...}

Example of a string:

This${ is }a clear${ and simple} example ${string}, where {${only}} only the \${highlighted} parts should be selected.

Expected result:

[ "${ is }" , "${ and simple}" , "${string}" , "${only}" ]


I've been able to define the regular expression to select all the tokens in the string :

/(\${\s?\S+\s?})/g

However I still can't figure out how to ignore the wole ESCAPED item, as well as the extra braket returned in ${result-4}

I've been performing my tests here: https://regex101.com/r/XsQFqS/1

I would apprecciate any kind of help with this.

colxi
  • 7,640
  • 2
  • 45
  • 43
  • Are you trying to extract or replace or ...? Try [`\\(?:\${\s?\S+\s?})|(\${\s?\S+\s?})`](https://regex101.com/r/XsQFqS/2) – revo May 17 '18 at 21:45
  • 1
    Within ES2018 compatible JS environment, you may use [`/(?<=(?<!\\)(?:\\{2})*)\${[^{}]*}/g`](https://regex101.com/r/3Y9jUq/3). But in other cases, you can rely on capturing, [`/((?:^|[^\\])(?:\\{2})*)(\${[^{}]*})/g`](https://regex101.com/r/3Y9jUq/2) – Wiktor Stribiżew May 17 '18 at 21:50
  • The only proposed expresion working is the ES2018 one, provided by @WiktorStribiżew , but it disallows curly brakets inside the delimiters. I've been able to simplify it to :```/(?<!\\)\${[^{}]*}/g``` , but still, is pretty limiting. – colxi May 17 '18 at 22:15
  • 1
    This "simplified" regex will match unexpected strings like ``\\${content}`` (here, a backslash preceded the delimiter that must be matched). Also, what do you mean by not supporting braces inside? How do you plan to detect the delimiter right-hand boundary if there can be braces? Also, you do not really need the lookbehind. **What is your end goal**? What is the **expected result** for the sample string above? – Wiktor Stribiżew May 18 '18 at 05:07
  • I guess you are right. It has total sense. Thanks for your time. If you post it as a formal anwser i close the question with it. – colxi May 18 '18 at 05:17

1 Answers1

0

In practical terms, it seems to be impossible to match only the required elements using a basic JavaScript regex. However, it can be done with the old *SKIP what's to avoid trick using capture groups, i.e. What_I_want_to_avoid|(What_I_want_to_match), like this:

#What_I_want_to_avoid: escaped elemets (odd no. of escape characters)
(?:[^\\]\\(?:\\\\)+|[^\\]\\)\${[^{}]*}
|
#What_I_want_to_match: unescaped element (or even no. of escape characters)
[^\\](?:\\\\)*(\${[^{}]*})

Again, the key idea here is to completely disregard the overall matches returned by the regex engine: $0 is the trash bin. Instead, we only need to check capture group $1, which, when set, contains what we are looking for.

Test Demo

const regex = /(?:[^\\]\\(?:\\\\)+|[^\\]\\)\${[^{}]*}|[^\\](?:\\\\)*(\${[^{}]*})/g;
const str = `This\${ is }a clear\${ and simple} example \${string}, where {\${only}} only the \\\${highlighted} parts should be selected  \\\\\${allowing} escaping and unescaping: \\\\\\\${not}, \\\\\\\\\${yes}`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    m.forEach((match, groupIndex) => {
      if(groupIndex && match)
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}
wp78de
  • 18,207
  • 7
  • 43
  • 71
  • The idea is to skip the scaped items, and your code is returning them. – colxi May 18 '18 at 08:51
  • @colxi actually, you write "trying to find" and "Expected extractions" in the OP. Sounds a whole lot like matching, or what do I miss? – wp78de May 18 '18 at 09:04
  • I'm sorry if my description is not clear enougth. I've edited. What i'm trying to get is only the elements that are not escaped. – colxi May 18 '18 at 09:13
  • @colxi Isn't this exactly what my pattern does? Have you tried the Test/Demo? Are the green $1 values not what you want? – wp78de May 18 '18 at 09:16
  • I think i need some coffee. my apologies. – colxi May 18 '18 at 09:20