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 '¶m' in my string and replace it with 'John', unless the '&' character is preceded with the escape character '\'. Example: "My name is ¶m and my parameter is called \¶m." -> "My name is John and my parameter is called ¶m". What would be the regular expression to catch all the substrings that contain the '&', then my parameter's name, and without the preceding '\'?
-
The problem then becomes more complex. How would you literally put a backslash and the expanded value of ¶m? Perhaps \\¶m ? Ok, then you need to notice two. No wait, how do you do a backslash, and then literal ¶m. Oh, that would be \\\¶m. You really need to do a full left-to-right parse. – Randal Schwartz May 30 '21 at 21:40
2 Answers
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
).

- 64,680
- 7
- 105
- 121
To keep the character before ¶m
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 ¶m
and in this case we match at the beginning of the string instead.
Try this:
void main() {
final template = 'My name is ¶m and my parameter is called \\¶m.';
final populatedTemplate = template.replaceAllMapped(RegExp(r'(^|[^\\])¶m\b'), (match) {
return '${match.group(1)}John';
});
final result = populatedTemplate.replaceAll(RegExp(r'\\¶m\b'), 'John');
print(result);
}

- 10,773
- 7
- 38
- 60