Regex Replace Multiple Groups

Javascript Regex replacing multiple groups

When replacing, we usually match and capture what we need to keep (to be able to refer to the captured values with backreferences) and only match what you do not need to keep.

In your case, you need to just put the punctuation into the replacement pattern:

.replace(/{\s*\[(\w*)\]\s*(\w*)\s*\(([\w\s]*)\)\s*}/g, "{[a]$1b$2(c)$3)}")
^^ ^ ^ ^ ^^

See the regex demo

Regexp: replace multiple groups with unknown groups number

You may use single regex replacement using a \G based regex:

use strict;
use warnings;

my $s = 'function (foo, bar, some, other) {';
$s =~ s/(?:\G(?!\A),?|function\s*\()\s*\K(\w+)/$1:any/g;
print $s;

See an online Perl demo

Pattern details:

  • (?:\G(?!\A),?|function\s*\() - either the end of the previous successful match and an optional , (matched with \G(?!\A),?) or (|) function substring followed with 0+ whitespaces and then a literal ( (matched with function\s*\()
  • \s* - zero or more whitespaces
  • \K - match reset operator discarding the whole text matched so far from the match buffer
  • (\w+) - Group 1: one or more word chars.

How to replace multiple matches / groups with regexes?

You can use a replacement by lambda, mapping the keywords you want to associate:

>>> re.sub(r'(is)|(life)', lambda x: {'is': 'are', 'life': 'butterflies'}[x.group(0)], "There is no life in the void.")
'There are no butterflies in the void.'

Regex replace multiple groups

Given a dictionary that defines your replacements:

IDictionary<string, string> map = new Dictionary<string, string>()
{
{"&","__amp"},
{"#","__hsh"},
{"1","5"},
{"5","6"},
};

You can use this both for constructing a Regular Expression, and to form a replacement for each match:

var str = "a1asda&fj#ahdk5adfls";
var regex = new Regex(String.Join("|",map.Keys));
var newStr = regex.Replace(str, m => map[m.Value]);
// newStr = a5asda__ampfj__hshahdk6adfls

Live example: http://rextester.com/rundotnet?code=ADDN57626

This uses a Regex.Replace overload which allows you to specify a lambda expression for the replacement.


It has been pointed out in the comments that a find pattern which has regex syntax in it will not work as expected. This could be overcome by using Regex.Escape and a minor change to the code above:

var str = "a1asda&fj#ahdk5adfls";
var regex = new Regex(String.Join("|",map.Keys.Select(k => Regex.Escape(k))));
var newStr = regex.Replace(str, m => map[m.Value]);
// newStr = a5asda__ampfj__hshahdk6adfls

Replacing only the captured group using re.sub and multiple replacements

You can use a lookbehind and lookahead based regex and then a lambda function to iterate through replacements words:

>>> words = ['Swimming', 'Eating', 'Jogging']
>>> pattern = re.compile(r'(?<=I love )\w+(?=\.)')
>>> print pattern.sub(lambda m: words.pop(0), string)
'I love Swimming. I love Eating. I love Jogging.'

Code Demo

Regex replace multiple groups with wildcards

I don't understand why are you concatenating patterns and then performin so many searches in an array.

Can't you just apply each pattern individually like this?

var rules = new Dictionary<string, string>
{
{@"F\S+", "Replace 1"},
{@"\S+z", "Replace 2"},
};

string s = "Foo bar baz";
var result = rules.Aggregate(s, (seed, rule) => Regex.Replace(seed, rule.Key, m => rule.Value));

EDIT

Your match.Groups.Count is always one because there are no groups defined in your matches and the values is the entire matched string as described on MSDN. In other words, your GetMatchIndex method does nothing.

You could try transforming your patterns into named groups like this:

var patterns = rules.Select((kvp, index) => new 
{
Key = String.Format("(?<{0}>{1})", index, kvp.Key),
Value = kvp.Value
};

Having this array, in GetMatchIndex method you'd just parse the group name as being the index of the matched pattern:

private static int GetMatchIndex(Regex regex, Match match)
{
foreach(var name in regex.GetGroupNames())
{
var group = match.Groups[name];
if(group.Success)
return int.Parse(name); //group name is a number
}
return -1;
}

Now, you can use it like this:

var pattern = String.Join("|", patterns.Select(x => x.Key));
var regex = new Regex(pattern);
return regex.Replace(input, pattern, m =>
{
var index = GetMatchIndex(regex, m);
return patterns[index].Value;
});

Replace capture group of dynamic size

You can use the sticky flag y (but Internet Explorer doesn't support it):

s = s.replace(/(^https?:\/\/.*?\/path1\/?|(?!^))./gy, '$1*')

But the simplest (and that is supported everywhere), is to use a function as replacement parameter.

s = s.replace(/^(https?:\/\/.+\/path1\/?)(.*)/, function (_, m1, m2) {
return m1 + '*'.repeat(m2.length);
});

For the second case, you can simply check if there's an @ after the current position:

s = s.replace(/.(?=.*@)/g, '*');


Related Topics



Leave a reply



Submit