PowerShell Core v6.1.0+ supports passing a script block as the replacement operand of the
-replace operator; the script block is invoked for each match found, and its output forms the replacement string, thereby enabling algorithmic replacements (rather than merely textual ones):
'foo_10.dat' -replace '(.*)_([0-9]+)(\.dat)', {
'{0}{1}{2}' -f $_.Groups[1].Value,
([int] $_.Groups[2].Value + 3),
$_.Groups[3].Value
}
The above yields:
foo13.dat
Note how 3 was added to 10 (and the underscore was removed):
$_ inside the script block is a [System.Text.RegularExpressions.Match] instance representing the results of the match; e.g., $_.Value represents the full match, whereas $_.Groups[1].Value represents what the 1st capture group matched.
The functionality is built on the [regex] .NET type's .Replace() method, which can also used directly (but less easily) in earlier PowerShell versions - see below.
In Windows PowerShell you have two options:
Use the -match operator first and then perform the transformation in a separate statement based on the match information reflected in the automatic $Matches variable, as suggested by kuujinbo:
$null = 'foo_10.dat' -match '(.*)_([0-9]+)(\.dat)' # match first
'{0}{1}{2}' -f $Matches.1, ([int] $Matches.2 + 3), $Matches.3 # build via $Matches
Use the .NET framework directly, with a script block passed as a delegate (callback function) to the above-mentioned [regex]::Replace() method, as suggested by Ansgar Wiechers:
([regex] '(.*)_([0-9]+)(\.dat)').Replace('foo_10.dat', {
param($match)
'{0}{1}{2}' -f $match.Groups[1].Value, ([int] $match.Groups[2].Value + 3), $match.Groups[3].Value
})
- Note how a formal parameter -
param($match) - must be declared here in order to access the match results, whereas the pure PowerShell solution at the top was able to use $_, as usual.
-matchoperator:'abc_123.dat' -match '(.*)_([0-9]+)(.dat)' | out-null;$matches[1] + "($(([int]::Parse($matches[2]) + 3)))" + $matches[3];