-2

I'm trying to implement the escape character functionality in a macro generator I'm writing in Dart. For example, I would like the program to grab all the occurrences of '&param' in my string and replace it with 'John', unless the '&' character is preceded with the escape character '\'. Example: "My name is &param and my parameter is called \&param." -> "My name is John and my parameter is called &param". What would be the regular expression to catch all the substrings that contain the '&', then my parameter's name, and without the preceding '\'?

Harnold
  • 1
  • 1
  • 3
  • The problem then becomes more complex. How would you literally put a backslash and the expanded value of &param? Perhaps \\&param ? Ok, then you need to notice two. No wait, how do you do a backslash, and then literal &param. Oh, that would be \\\&param. You really need to do a full left-to-right parse. – Randal Schwartz May 30 '21 at 21:40

2 Answers2

0

It's possible to match that, even avoiding escapes of backslashes, as:

var re = RegExp(r"(?<!(?:^|[^\\])(?:\\{2})*\\)&\w+");

This uses negative lookbehind to find a & followed by word-characters, and not preceded by an odd number of backslashes.

More likely, you want to also recognize double-backslashes and convert them to single-backslashes. That's actually easier if you try to find all matches, because then you know all preceding double-backslashes are part of an earlier match:

var re = RegExp(r"\\\\|(?<!\\)&\w+");

This, when used as re.allMatches will find all occurrences of \\ and &word where the latter is not preceded by an odd number of backslashes.

var _re = RegExp(r"\\\\|(?<!\\)&(\w+)");
String template(String input, Map<String, String> values) {
  return input.replaceAllMapped(_re, (m) {
    var match = m[0]!;
    if (match == r"\\") return r"\";
    var replacement = values[m[1]!];
    if (replacement != null) return replacement;
    // do nothing for undefined words.
    return match;
  });
}

(You might also want to allow something like &{foo} if parameters can occur next to other characters, like &{amount)USD).

lrn
  • 64,680
  • 7
  • 105
  • 121
-1

To keep the character before &param when it matches a non-backslash character you need to use so called capturing groups. These are are subexpressions of a regular expression inside parentheses. To use capturing groups in Dard you need to use the method replaceAllMapped. We also have the case when the template starts with &param and in this case we match at the beginning of the string instead.

Try this:

void main() {
    final template = 'My name is &param and my parameter is called \\&param.';
    final populatedTemplate = template.replaceAllMapped(RegExp(r'(^|[^\\])&param\b'),  (match) {
        return '${match.group(1)}John';
    });
    final result = populatedTemplate.replaceAll(RegExp(r'\\&param\b'),  'John');
    print(result);
}
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60