Powershell - substituir com comportamento estranho

Oct 05 2020

Isso está me deixando louco! Gostaria de receber qualquer indicação sobre o que está acontecendo, por favor!

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

Isso produz a seguinte saída:

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

Estou tentando identificar / combinar sequências de caracteres em um caminho que começa com o literal '$' e continua até, mas não inclui um ponto literal "." Caracteres. No código de exemplo acima, a string seria "$ connection".

Em seguida, preciso envolver essa string entre aspas simples, portanto, no exemplo acima, o valor $ newChunk se tornaria '$ connection' incluindo as aspas simples.

Em seguida, preciso substituir o valor correspondente pelo novo valor entre aspas simples na string original. Não importa o que eu tente (mesmo com o método [regex] :: match também), as aspas simples são removidas. Então, efetivamente, estou tentando transformar:

aaa.bbb.$connection.ccc.ddd

para dentro

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

Estou usando o PowerShell 7.1 e gostaria muito que alguém me dissesse por que isso não funciona. Obrigado!

Respostas

4 RyszardCzech Oct 05 2020 at 01:52

Usar

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

Veja a prova .

Explicação

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

O $&é o espaço reservado para toda a partida.

1 mklement0 Oct 05 2020 at 04:53

A resposta útil de Ryszard Czech é definitivamente a melhor solução : genericamente, referir-se ao que o operador baseado em regex -replace combinou, em seu operando de substituição, com placeholder$& é a solução mais simples e robusta.

Veja esta resposta para outros espaços reservados que você pode usar, como o que precedeu ( $`) ou sucedeu ( $') a correspondência, ou o que um grupo de captura correspondeu (por exemplo $1).


Quanto ao que você tentou :

  • Em vez de usar seu regex \$.+?(?=\.) diretamente com o operador baseado em regex , você usou o resultado literal de uma chamada explícita como o operando de pesquisa (primeiro operando RHS) para , que é novamente interpretado como um regex.-replace[regex].Match()-replace

    • No entanto, para usar uma string literalmente como o operando de -replace pesquisa , quaisquer metacaracteres regex - ou seja, caracteres com significado sintático especial - devem ter \escape , como o literal $em sua string, o que você pode fazer com[regex]::Escape($s)
  • Além disso, você usou um operando de substituição que tinha um char embutido $. que você pretendia ser interpretado literalmente , mas $no operando de substituição está um metacaractere , referindo-se a marcadores de posição como $&.

    • Para usar uma string literalmente como operando de -replace substituição , você deve escapar de forma programática os caracteres incorporados $. as $$[1] :
      A abordagem mais simples é usar o [string]método de substituição literal-substring do tipo .Replace():

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

Assim, sua abordagem original teria que usar o seguinte comando - mas observe que a solução de Ryszard é muito mais simples no geral:

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

[1] Situacionalmente, você pode escapar sem escapar, porque um $token com prefixo que não é reconhecido como um espaço reservado é deixado intocado (por exemplo, 'bar' -replace 'r', '$x'se comporta da mesma forma que 'bar' -replace 'r', '$$x'), mas a única solução robusta é escapar literalmente dos $caracteres. dobrando-os.