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

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

Когда фактический результат мне нужен

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

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

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

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

1
Mark Henderson 5 Фев 2020 в 02:46

4 ответа

Лучший ответ

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

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

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

Более подробная информация здесь: https://vexx32.github.io/2019 / 03 / 20 / PowerShell - Заменить - Operator /

3
Brandon Olin 5 Фев 2020 в 00:01

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

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

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

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

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

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

    • Case- нечувствительный .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
mklement0 5 Фев 2020 в 18:53

Я не смог найти документально подтвержденное, но правило экранирования в стиле «Visual Basic» сработало, повторяйте символ.

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

1
Dane W 4 Фев 2020 в 23:57

Это сбивает с толку, как эти коды не документированы в «об операторах сравнения». За исключением того, что у меня есть закрытый отчет об ошибках под ними, если вы посмотрите: «Ух, где все эти 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
js2010 5 Фев 2020 в 19:03