Powershell -sostituisce il comportamento strano

Oct 05 2020

Questo mi sta facendo impazzire! Apprezzerei qualsiasi suggerimento su cosa sta succedendo, per favore!

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

Questo produce il seguente output:

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

Sto cercando di identificare / far corrispondere sequenze di caratteri in un percorso che inizia con il letterale "$" e continua fino a, ma non include un punto letterale "." char. Nel codice di esempio sopra la stringa sarebbe "$ connection".

Quindi ho bisogno di racchiudere quella stringa tra virgolette singole, quindi nell'esempio sopra il valore $ newChunk diventerebbe '$ connection' comprese le virgolette singole.

Successivamente, è necessario sostituire il valore corrispondente con il nuovo valore tra virgolette singole nella stringa originale. Non importa cosa provo (lo stesso con il metodo [regex] :: match), le virgolette singole vengono rimosse. Quindi, effettivamente, sto cercando di trasformare:

aaa.bbb.$connection.ccc.ddd

in

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

Usando Powershell 7.1 e apprezzerei davvero che qualcuno mi dicesse perché questo non funziona. Grazie!

Risposte

4 RyszardCzech Oct 05 2020 at 01:52

Uso

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

Vedi la prova .

Spiegazione

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

Il $&è il segnaposto per l'intera partita.

1 mklement0 Oct 05 2020 at 04:53

L'utile risposta di Ryszard Czech è sicuramente la soluzione migliore : riferirsi genericamente a ciò che l' operatore basato su espressioni regolari ha -replace abbinato, nel suo operando sostitutivo, con segnaposto$& è la soluzione più semplice e robusta.

Vedi questa risposta per altri segnaposto che puoi usare, come ciò che ha preceduto ( $`) o riuscito ( $') la corrispondenza, o ciò che un gruppo di acquisizione corrisponde (ad esempio $1).


Per quanto riguarda quello che hai provato :

  • Invece di usare la tua regex \$.+?(?=\.) direttamente con l' operatore basato su regex , hai usato il risultato letterale di una chiamata esplicita come operando di ricerca (primo operando RHS) per , che viene poi nuovamente interpretato come regex.-replace[regex].Match()-replace

    • Tuttavia, per poter utilizzare una stringa alla lettera come operando di -replace ricerca , qualsiasi metacarattere regex , ovvero caratteri con un significato sintattico speciale, deve essere \preceduto da caratteri di escape , come il verbatim $nella stringa, cosa che puoi fare con[regex]::Escape($s)
  • Inoltre, hai utilizzato un operando sostitutivo che aveva un carattere incorporato $. che volevi interpretare alla lettera , ma $nell'operando sostitutivo c'è un metacarattere , che si riferisce a segnaposto come $&.

    • Per utilizzare una stringa verbatim come operando -replace sostitutivo , è necessario eseguire l' escape dei $caratteri incorporati a livello di codice. come $$[1] :
      L'approccio più semplice è quello di utilizzare il [string]metodo di sostituzione letterale-sottostringa del tipo .Replace():

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

Pertanto, il tuo approccio originale avrebbe dovuto utilizzare il seguente comando, ma tieni presente che la soluzione di Ryszard è molto più semplice nel complesso:

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

[1] Situazionalmente potresti $cavartela senza scappare, perché un token -prefixed che non è riconosciuto come segnaposto viene lasciato intatto (ad esempio, 'bar' -replace 'r', '$x'si comporta allo stesso modo di 'bar' -replace 'r', '$$x'), ma l'unica soluzione valida è sfuggire ai $caratteri letterali . raddoppiandoli.