Заменить строки в свойствах пользовательских объектов PSObject в массиве

Я прочитал CSV-файл в массив объектов (используя Import-Csv). Если я запишу эти данные обратно на диск с помощью Export-Csv, я получу именно то, что ожидал, - хорошо отформатированный CSV.

Теперь мне нужно изменить некоторые данные в этом CSV. Одна из них - это струны, которые необходимо заменить. Но если я сделаю простое:

$thisIsTheArrayOfObjects -replace "Old ID", "New ID" 

в результате получается массив СТРОК. (замена произошла, но каким-то образом все мои объекты в массиве были преобразованы в строки)

Конечно, теперь Export-Csv не дает ожидаемого результата. Он просто экспортирует файл со всей длиной строк в моем массиве.

Как заменить строки в свойствах PSOBJECTS в массиве?


person user7376515    schedule 21.10.2019    source источник


Ответы (1)


Как заменить строки в свойствах PSOBJECTS в массиве?

Вы делаете это для каждого объекта.

$thisIsTheArrayOfObjects | ForEach-Object {
    $_.foo = $_.foo -replace "Old ID" , "New ID" # replace string in a property
    $_                                           # output the object back onto the pipeline
}

Имейте в виду, что с -replace есть две ошибки:

  • Он работает с регулярным выражением. Технически вы должны экранировать первый параметр ([regex]::escape("Old ID")) с помощью регулярного выражения, если хотите выполнить буквальную замену, если только «Старый идентификатор» не содержит каких-либо специальных символов в регулярном выражении. Если он исходит от ввода пользователя, всегда разумно избегать его.
  • Он нечувствителен к регистру.

Чтобы делать буквальные замены с учетом регистра, используйте .NET-native String.Replace(), который также доступен:

$thisIsTheArrayOfObjects | ForEach-Object {
    $_.foo = $_.foo.Replace("Old ID", "New ID") # replace string in a property
    $_                                          # output the object back onto the pipeline
}

Чтобы применить операцию к каждому столбцу в данных CSV, вы должны создать вложенный цикл. Командлет Get-Member может помочь. Принцип остается таким же, как указано выше.

Import-Csv "input.csv" -PipelineVariable row | ForEach-Object {
    $row | Get-Member -MemberType NoteProperty -PipelineVariable col | ForEach-Object {
        $colname = $col.Name
        $row.$colname = $row.$colname -replace "Old ID", "New ID"
        $row
    }
} # | Export-Csv "output.csv"

Обратите внимание на использование переменных конвейера, чтобы избежать $_ путаницы внутри внутреннего цикла.

person Tomalak    schedule 21.10.2019
comment
Большое спасибо за очень быстрый ответ. Но есть еще одна проблема. Когда я читаю данные из csv, для каждого объекта существуют сотни свойств, и они могут даже меняться в зависимости от загруженного csv. Поэтому имя свойства foo в вашем примере недоступно ... Могу ли я перебрать все свойства сейчас? - person user7376515; 21.10.2019
comment
Проблема не в перечислении объектов (с этим прекрасно справляются операторы PowerShell), а в том, что операция замены применяется ко всему объекту, а не к значению одного из его свойств. Из-за этого объект сначала преобразуется в его строковое представление, а затем к полученной строке применяется операция замены. - person Ansgar Wiechers; 21.10.2019
comment
Это, вероятно, более элегантный подход. - person Ansgar Wiechers; 21.10.2019
comment
Много способов снять шкуру с кошки. - person Tomalak; 21.10.2019