Powershell -замена, когда строка замены содержит $ + - PullRequest
1 голос
/ 05 февраля 2020

Я делаю замену строки в PowerShell. У меня нет контроля над строками, которые заменяются, но я могу воспроизвести проблему, которая у меня возникла следующим образом:

> 'word' -replace 'word','@#$+'
@#word

Когда фактический вывод мне нужен,

> 'word' -replace 'word','@#$+'
@#$+

Строка $+ расширяется до слова, подлежащего замене, и я никак не могу найти способ предотвратить это. Я попытался экранировать $ с помощью \ (как если бы это было регулярное выражение), с обратным ключом ` (как и в обычном способе PowerShell). Например:

> 'word' -replace 'word',('@#$+' -replace '\$','`$')
@#`word

Как заменить на литерал $+ в PowerShell? Для чего это стоит, я использую PowerShell Core 6, но это также воспроизводимо в PowerShell 5.

Ответы [ 4 ]

3 голосов
/ 05 февраля 2020

Вместо использования оператора -replace вы можете использовать метод .Replace() следующим образом:

PS> 'word'.Replace('word','@#$+')
@#$+

Метод .Replace() происходит из класса. NET String, тогда как -Replace оператор реализован с использованием System.Text.RegularExpressions.Regex.Replace().

Подробнее здесь: https://vexx32.github.io/2019/03/20/PowerShell-Replace-Operator/

1 голос
/ 05 февраля 2020

Это сбивает с толку, как эти коды не документированы в "об операторах сравнения". За исключением того, что у меня есть закрытый отчет об ошибках под ними, если вы посмотрите: «Ух, где все эти 2-аргументные коды задокументированы?». https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-7 Это стало моей ссылкой. «$ +» означает «Заменяет последний перехват» Удвоение знака доллара работает, «заменяет один литерал« $ »:

'word' -replace 'word','@#$$+'

@#$+

или используйте версию второго аргумента в блоке сценариев в PS 6 и выше (может быть медленнее):

'word' -replace 'word',{'@#$+'}
1 голос
/ 05 февраля 2020

Оператор PowerShell -replace :

  • использует регулярное выражение (обычный выражение) как поиск (1-й) операнд

    • , если вы хотите использовать строку поиска дословно , экранируйте ее с помощью [regex]::Escape() (в строковых литералах можно альтернативно \ -создать отдельные символы, которые в противном случае были бы интерпретированы как метасимволы регулярных выражений).
  • использует не-литеральная строка, которая может относиться к тому, что регулярное выражение совпало как замена (2-й) операнд через $ с префиксом такие токены, как $& или $+ (см. ссылку выше или Подстановки в регулярных выражениях ).

    • , если вы хотите использовать строку замены дословно , двойной любой $ символов. в нем (см. Ниже).

Если ваша строка поиска и ваша замена цементная колонна должна использоваться дословно , рассмотрите возможность использования типа *1068*.Replace() метод вместо этого, как показано в полезный ответ Брэндона Олина .

  • Предупреждение: .Replace() чувствительно к регистру - чувствительно по умолчанию, тогда как -replace нечувствительно к регистру * нечувствительно (как PowerShell обычно ); используйте другую перегрузку .Replace() для нечувствительности к регистру или, наоборот, используйте вариант -creplace в PowerShell для получения чувствительности к регистру.

    • регистр- нечувствительный .Replace() пример:
      'FOO'.Replace('o', '@', 'CurrentCultureIgnoreCase')
  • .Replace() быстрее, чем -replace, хотя это имеет значение только в циклах с большим числом итераций.

Если в вашем случае использовать оператор -replace , вы можете использовать метод .Replace() для требуемого экранирования операнда -replace замены:

# *Doubling* the `$` in the replacement operand ensures that they're used verbatim.
'word' -replace 'word', '@#$+'.Replace('$', '$$')

Вы также можете сделать это с помощью вложенной -replace операции, но это становится громоздким (\$ экранирует $ в регулярном выражении; $$ представляет собой single $ в строке замены):

# Same as above.
'word' -replace 'word', ('@#$+' -replace '\$', '$$$$')

Другими словами:

'word'.Replace('word','@#$+')

:

'word' -creplace [regex]::Escape('word'),'@#$+'.Replace('$', '$$')

Однако, как указано, если и строка поиска, и операнд замены должны использоваться дословно, то использование .Replace() является предпочтительным, так как для краткости и производительности.

1 голос
/ 05 февраля 2020

Не удалось найти документально подтвержденное, но правило экранирования в стиле "Visual Basi c" сработало, повторите символ.

'word' -replace 'word','@#$$+' дает вам: @#$+

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...