问题
This is driving me nuts! Would appreciate any pointers as to what is going on, please!
$alpha = 'aaa.bbb.$connection.ccc.ddd'
$s = [regex]::match($alpha,"\$.+?(?=\.)").Value
"Alpha is: $alpha"
"Matched chunk is: $s"
$newChunk = "'" + $s + "'"
"New chunk is: $newChunk"
$beta = $alpha -replace $s,$newChunk
"Beta is: $beta"
This produces the following output:
Alpha is: aaa.bbb.$connection.ccc.ddd
Matched chunk is: $connection
New chunk is: '$connection'
Beta is: aaa.bbb.$connection.ccc.ddd
I am trying to identify/match character sequences in a path that begin with the literal '$' and continue until, but does not include a literal dot "." char. In the example code above the string would be "$connection".
Then I need to wrap that string in single quotes, so in the example above the $newChunk value would become '$connection' including the single quotes.
Next, I need to replace the matched value with the new single quoted value in the original string. No matter what I try (same with [regex]::match method too), the single quotes are stripped out. So, effectively, I am trying to turn:
aaa.bbb.$connection.ccc.ddd
into
aaa.bbb.'$connection'.ccc.ddd
Using Powershell 7.1 and would really appreciate someone telling me why this does not work. Thanks!
回答1:
Use
$beta = $alpha -replace '\$[^.]+', "'$&'"
See proof.
Explanation
--------------------------------------------------------------------------------
\$ '$'
--------------------------------------------------------------------------------
[^.]+ any character except: '.' (1 or more times
(matching the most amount possible))
The $&
is the placeholder for the entire match.
回答2:
Ryszard Czech's helpful answer is definitely the best solution: generically referring to what the regex-based -replace operator matched, in its replacement operand, with placeholder $&
is the simplest and most robust solution.
See this answer for other placeholders you can use, such as what preceded ($`
) or succeeded ($'
) the match, or what a capture group matched (e.g. $1
).
As for what you tried:
Instead of using your regex
\$.+?(?=\.)
directly with the regex-based -replace operator, you used the verbatim result of an explicit[regex].Match()
call as the search operand (first RHS operand) for-replace
, which is then again interpreted as a regex.- However, in order to use a string verbatim as the
-replace
search operand, any regex metacharacters - i.e., characters with special syntactic meaning - must be\
-escaped, such as the verbatim$
in your string, which you can do with [regex]::Escape($s)
- However, in order to use a string verbatim as the
Additionally, you used a replacement operand that had an embedded
$
char. that you meant to be interpreted verbatim, but$
in the replacement operand is a metacharacter, referring to placeholders such as$&
.In order to use a string verbatim as the
-replace
replacement operand, you must programmatically escape embedded$
chars. as$$
[1]:
The simplest approach is to use the[string]
type's literal-substring replacement method,.Replace()
:$replacementOperand = '$foo' 'value is: (value)' -replace '\(value\)', $replacementOperand.Replace('$', '$$')
Thus, your original approach would have had to use the following command - but do note that Ryszard's solution is much simpler overall:
$beta = $alpha -replace [regex]::replace($s), $newChunk.Replace('$', '$$')
[1] Situationally you may get away without escaping, because a $
-prefixed token that isn't recognized as a placeholder is left untouched (e.g., 'bar' -replace 'r', '$x'
behaves the same as 'bar' -replace 'r', '$$x'
), but the only robust solution is to escape verbatim $
chars. by doubling them.
来源:https://stackoverflow.com/questions/64198435/powershell-replace-giving-strange-behaviour