Powershell -replace дает странное поведение

Oct 05 2020

Это сводит меня с ума! Буду признателен за любые указатели на то, что происходит, пожалуйста!

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

Это дает следующий результат:

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

Я пытаюсь идентифицировать / сопоставлять последовательности символов в пути, которые начинаются с буквального символа '$' и продолжаются до тех пор, пока буквальная точка "не включается". char. В приведенном выше примере кода строка будет «$ connection».

Затем мне нужно заключить эту строку в одинарные кавычки, поэтому в приведенном выше примере значение $ newChunk станет «$ connection», включая одинарные кавычки.

Затем мне нужно заменить совпадающее значение новым значением в одиночных кавычках в исходной строке. Независимо от того, что я пробую (то же самое и с методом [regex] :: match), одинарные кавычки удаляются. Итак, по сути, я пытаюсь превратить:

aaa.bbb.$connection.ccc.ddd

в

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

Используя Powershell 7.1, я был бы очень признателен, если бы кто-нибудь сказал мне, почему это не работает. Спасибо!

Ответы

4 RyszardCzech Oct 05 2020 at 01:52

Использовать

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

Смотрите доказательство .

Объяснение

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

Это $&заполнитель для всего совпадения.

1 mklement0 Oct 05 2020 at 04:53

Полезный ответ Рышарда Чеха, безусловно, является лучшим решением : в целом ссылка на то, что оператор на основе регулярного выражения -replace сопоставил в своем замещающем операнде с заполнителем,$& является самым простым и надежным решением.

См. Этот ответ, чтобы узнать о других заполнителях, которые вы можете использовать, например о том, что предшествовало ( $`) или успешно ( $') совпадению, или о том, что соответствует группе захвата (например $1).


Что касается того, что вы пробовали :

  • Вместо того, чтобы использовать ваше регулярное выражение \$.+?(?=\.) напрямую с оператором на основе регулярного выражения , вы использовали дословный результат явного вызова в качестве операнда поиска (первый операнд RHS) для , который затем снова интерпретируется как регулярное выражение.-replace[regex].Match()-replace

    • Однако, чтобы дословно использовать строку в качестве операнда -replace поиска , любые метасимволы регулярных выражений, т. Е. Символы со специальным синтаксическим значением, должны быть \экранированы , например дословно $в вашей строке, что вы можете сделать с[regex]::Escape($s)
  • Кроме того, вы использовали заменяющий операнд со встроенным $символом. что вы хотели интерпретировать дословно , но $в операнде замены есть метасимвол , относящийся к заполнителям, таким как $&.

    • Чтобы дословно использовать строку в качестве операнда -replace замены , необходимо программно экранировать встроенные $символы. as $$[1] :
      Самый простой подход - использовать [string]метод замены литерала-подстроки типа .Replace():

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

Таким образом, ваш исходный подход должен был бы использовать следующую команду, но обратите внимание, что решение Ryszard в целом намного проще:

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

[1] Ситуационно вы можете уйти , не убежать, потому что $-prefixed маркер , который не распознается как заполнитель остается нетронутым (например, 'bar' -replace 'r', '$x'ведет себя так же , как 'bar' -replace 'r', '$$x'), но единственным надежным решением является избежать дословные $символов. удвоив их.