Powershell-Ersatz für seltsames Verhalten

Oct 05 2020

Das macht mich verrückt! Würde mich über Hinweise freuen, was los ist, bitte!

$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"

Dies erzeugt die folgende Ausgabe:

Alpha is: aaa.bbb.$connection.ccc.ddd
Matched chunk is: $connection New chunk is: '$connection'
Beta is: aaa.bbb.$connection.ccc.ddd

Ich versuche, Zeichenfolgen in einem Pfad zu identifizieren / abzugleichen, die mit dem Literal '$' beginnen und bis fortgesetzt werden, aber keinen Literalpunkt "enthalten." verkohlen. Im obigen Beispielcode wäre die Zeichenfolge "$ connection".

Dann muss ich diese Zeichenfolge in einfache Anführungszeichen setzen, damit im obigen Beispiel der Wert von $ newChunk zu '$ connection' wird, einschließlich der einfachen Anführungszeichen.

Als nächstes muss ich den übereinstimmenden Wert durch den neuen Wert in einfacher Anführungszeichen in der ursprünglichen Zeichenfolge ersetzen. Egal was ich versuche (das gleiche gilt auch für die Methode [regex] :: match), die einfachen Anführungszeichen werden entfernt. Also versuche ich effektiv, mich umzudrehen:

aaa.bbb.$connection.ccc.ddd

in

aaa.bbb.'$connection'.ccc.ddd

Verwenden Sie Powershell 7.1 und würde mich sehr freuen, wenn mir jemand sagt, warum dies nicht funktioniert. Vielen Dank!

Antworten

4 RyszardCzech Oct 05 2020 at 01:52

Verwenden

$beta = $alpha -replace '\$[^.]+', "'$&'"

Siehe Beweis .

Erläuterung

--------------------------------------------------------------------------------
  \$ '$'
--------------------------------------------------------------------------------
  [^.]+                    any character except: '.' (1 or more times
                           (matching the most amount possible))

Das $&ist der Platzhalter für das gesamte Spiel.

1 mklement0 Oct 05 2020 at 04:53

Die hilfreiche Antwort von Ryszard Czech ist definitiv die beste Lösung : Esist die einfachste und robusteste Lösung, sichgenerell auf das zu beziehen, was der auf Regex basierende -replaceOperator in seinem Ersatzoperanden mit dem Platzhalter$& abgeglichen hat.

Sehen Sie diese Antwort für andere Platzhalter Sie verwenden können, wie zum Beispiel , was voran ( $`) oder es gelungen ( $') das Spiel, oder was eine Capture - Gruppe angepasst (zB $1).


Was was Sie versucht :

  • Anstatt Ihre Regex \$.+?(?=\.) direkt mit dem Regex-basierten -replaceOperator zu verwenden , haben Sie das wörtliche Ergebnis eines expliziten [regex].Match()Aufrufs als Suchoperanden (erster RHS-Operand) für verwendet -replace, der dann erneut als Regex interpretiert wird.

    • Allerdings , um eine Zeichenfolge zu verwenden , wörtlich als Suchoperanden-replace , irgendwelche Regex Metazeichen - dh Zeichen mit spezieller syntaktischer Bedeutung - müssen \-escaped als wörtlich, wie $in der Zeichenfolge, die Sie tun können , mit[regex]::Escape($s)
  • Außerdem haben Sie einen Ersatzoperanden mit einem eingebetteten $Zeichen verwendet. dass Sie wörtlich interpretiert werden wollten , aber $im Ersetzungsoperanden ein Metazeichen ist , das sich auf Platzhalter wie $&.

    • Um eine Zeichenfolge zu verwenden , wörtlich als -replace Ersatz Operanden , müssen Sie programmatisch eingebettet entkommen $Zeichen. as $$[1] :
      Der einfachste Ansatz besteht darin, die [string]Ersetzungsmethode für Literal-Teilzeichenfolgen des Typs zu verwenden .Replace():

      $replacementOperand = '$foo'    
      'value is: (value)' -replace '\(value\)', $replacementOperand.Replace('$', '$$') 
      

Daher hätte Ihr ursprünglicher Ansatz den folgenden Befehl verwenden müssen - beachten Sie jedoch, dass die Lösung von Ryszard insgesamt viel einfacher ist:

$beta = $alpha -replace [regex]::replace($s), $newChunk.Replace('$', '$$')

[1] In bestimmten Situationen können Sie entkommen, ohne zu entkommen, da ein $Token mit Präfix, das nicht als Platzhalter erkannt wird, unberührt bleibt (z. B. 'bar' -replace 'r', '$x'sich genauso verhält wie 'bar' -replace 'r', '$$x'), aber die einzige robuste Lösung besteht darin, wörtlichen $Zeichen zu entkommen . indem man sie verdoppelt.