Powershell: замена в строках с использованием хеш-таблицы - PullRequest
3 голосов
/ 18 сентября 2011

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

$r = @{
    "dog" = "canine";
    "cat" = "feline";
    "eric" = "eric cartman"
}

Что мне делать дальше? Я пробовал это:

(Get-Content C:\scripts\test.txt) | Foreach-Object {
    foreach ( $e in $r.GetEnumerator() ) {
        $_ -replace $e.Name, $e.Value
    }
} | Set-Content C:\scripts\test.txt.out

Но он вообще не работает, он просто пишет каждую строку три раза, ничего не заменяя.

РЕДАКТИРОВАТЬ: Содержит test.txt:

dog
cat
eric

test.txt.out:

dog
dog
dog
cat
cat
cat
eric
eric
eric

Ответы [ 3 ]

7 голосов
/ 18 сентября 2011

Вот один из способов сделать это:

$file = Get-Content C:\scripts\test.txt
foreach ($e in $r) {
  $file = $file -replace $e.Name, $e.Value
}
Set-Content -Path C:\scripts\test.txt.out -Value $file

Причина, по которой вы видели каждую строку три раза, заключается в том, что вложенный цикл foreach. Операция замены выполнялась один раз для каждой записи хеш-таблицы для каждой строки в файле. Это не меняет исходный файл, но по умолчанию выводит результат замены (даже если ничего не изменилось).

Вы можете получить желаемую функциональность, сначала прочитав файл в переменную, а затем используя зацикливание, чтобы обновить эту переменную. Вам также не нужен отдельный цикл foreach для содержимого файла; замена может выполняться с полным текстом за один проход для каждой записи хеш-таблицы.

4 голосов
/ 28 февраля 2013

В зависимости от вашего файла и хеш-таблицы, вы можете рассмотреть различные варианты оптимизации:

  1. Вы можете создать регулярное выражение из коллекции ключей хеш-таблицы, например:

    $regexes = $r.keys | foreach {[System.Text.RegularExpressions.Regex]::Escape($_)}
    $regex = [regex]($r.Keys -join '|')    
    

    При этом вам не нужно было бы повторять каждый ключ, но теперь вам нужно знать, какой ключ вы выбрали, чтобы получить замену.С другой стороны, может быть быстрее выполнять замену строк вместо замены регулярных выражений (или что-то более сложное, например, процесс разделения строк и соединения).

  2. В Powershell вы можете вызвать.NET Regex::Replace function:

    string Replace (ввод строки, оценщик System.Text.RegularExpressions.MatchEvaluator)

    Вызывая этот метод, вы можете определить MatchEvaluator с помощьюблок сценариев выглядит так:

    $callback = { $r[$args[0].Value] }
    

    В блоке сценариев $args[0] является System.Text.RegularExpressions.Match, поэтому вы можете использовать его свойство Value для индексации в хеш-таблицу $r.

  3. Get-Content возвращает массив строк, который подходит для оператора -replace, но также подразумевает выполнение дополнительного цикла.[System.IO.File]::ReadAllText вместо этого вернет одну строку, поэтому регулярное выражение нужно анализировать только один раз.

    $file = [System.IO.File]::ReadAllText("C:\scripts\test.txt")
    
  4. Если вы использовали Get-Content, используйте $regex.Replace (вместо-replace) вам понадобится цикл:

    $file = $file | % { $regex.Replace($_, $callback) }
    

    Так как я не могу использовать один вызов на замену:

    $file = $regex.Replace($file, $callback)
    

Таким образом, полный сценарий:

$r = @{
    "dog" = "canine";
    "cat" = "feline";
    "eric" = "eric cartman"
}


$regexes = $r.keys | foreach {[System.Text.RegularExpressions.Regex]::Escape($_)}
$regex = [regex]($regexes -join '|')

$callback = { $r[$args[0].Value] }

$file = [System.IO.File]::ReadAllText("C:\scripts\test.txt")
$file = $regex.Replace($file, $callback)
Set-Content -Path C:\scripts\test.txt.out -Value $file
3 голосов
/ 30 октября 2012

Я получил это работать таким образом

foreach ($i in $HashTable.Keys) {
  $myString = $myString -replace $i, $HashTable[$i]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...