Powershell L oop через текстовый файл и разделенный двоеточием - PullRequest
1 голос
/ 26 февраля 2020

У меня есть текстовый файл с содержанием, аналогичным приведенному ниже:

----------------------------------------
Title: Textbook
Client: ABC
----------------------------------------
----------------------------------------
Title: Comic book
Client: DEF
----------------------------------------

Я хочу разбить каждую строку на двоеточие и сохранить левую сторону в переменной с именем «Заголовок» и правую сторону в другой переменной и и так далее, так что когда я печатаю вывод, я получаю что-то похожее на следующее:

$Title has been sold to $Client

Вот мой сценарий до сих пор. Я попробовал несколько примеров в Powershell, читающем несколько переменных из текстового файла , но это не удача, и я не могу понять, что не так с моим текущим скриптом.

$data = Get-Content "C:\Users\user\Downloads\test.log" | Where { $_ -notmatch '^-.*' -and $_ -notmatch '^\s*$' } 

$outputFromLoop = @() 
$data | foreach-object {

    $key, $value = ($_ -split ':',2).trim()
    $outputFromLoop[$key] = $value

}
$outputFromLoop

Ответы [ 4 ]

2 голосов
/ 26 февраля 2020

Я бы прочитал файл как одну большую многострочную строку, разделил ее на строки ------, чтобы получить отдельные записи, немного обновил формат (преобразовал двоеточия в знаки равенства и убрал некоторые пробелы), а затем использовал ConvertFrom-StringData для создания объектов, с которыми вы можете работать.

$RawText = Get-Content C:\Path\To\File.txt -raw
$Sales = $RawText -split '(?:^|[\r\n])-+(?:[\r\n]|$)' -replace '(Title|Client):\s*','$1='|Where{$_}|ForEach-Object{New-Object PSObject -Property (ConvertFrom-StringData $_)}
$Sales | ForEach-Object {
    "{0} was sold to {1}" -f $_.Title, $_.Client
}

В результате:

Textbook was sold to ABC
Comic book was sold to DEF

Кроме того, вы получаете массив объектов, который вы можете использовать для отслеживания продаж на одного клиента. или посмотрите, кто все что приобрел. (например, $Sales | Group Client).

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

Вот метод, использующий оператор switch:

$hash = [ordered]@{}
switch -regex -file test.log {
  '^-+' { if ($hash.Count -ne 0) { 
            "{0} has been sold to {1}" -f $hash.Title,$hash.Client
          }
          $hash = [ordered]@{} 
  }
  '^([^:]+):(.+)' { $key,$value = $matches[1].Trim(),$matches[2].Trim()
                    $hash.Add($key,$value) 
  }
}

Объяснение:

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

$matches будет заполняться строками, которые содержат : и не начинаются с -. Каждый раз, когда достигается строка, начинающаяся с -, таблица ha sh ($hash), содержащая Client и Title, будет извлекать свои значения и выводить их в строке с запрошенным форматом. Затем таблица ha sh повторно инициализируется.

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

Вы можете импортировать файл как csv и использовать: в качестве разделителя

$content = Import-Csv C:\temp\file.txt -Delimiter : -Header Field1, Field2 | ? { $_.Field1 -notmatch "-+" }

$i = 0
while ($i -lt $csv.Count) {

  $title = $csv[$i++].Field2
  $client = $csv[$i++].Field2
  Write-output "$title sold to $client"
}

#Prints to console:
Textbook sold to ABC
Comic book sold to DEF

Или вы можете прочитать в файле и получить только совпадающие Названия и Клиенты .. затем использовать тот же индекс для каждого для получить желаемый результат.

$content = Get-Content C:\temp\file.txt

$Titles = $content -match "Title: " | % { $_ -replace "Title: ", "" }
$Clients = $content -match "Client: " | % { $_ -replace "Client: ", ""}

if ($Titles.Length -ne $Clients.Length) {
    Write-Output "Not the same"
}

$outputFromLoop = @{}
for($i = 0; $i -lt $titles.Length; $i++) {
    Write-Output "$($Titles[$i]) sold to $($Clients[$i])"
    $outputFromLoop[$Titles[$i]] = $Clients[$i]
}

# Prints the same
Textbook sold to ABC
Comic book sold to DEF

$outputFromLoop:
Name                           Value                                                                                                                                                                                                                 
----                           -----                                                                                                                                                                                                                 
Textbook                       ABC                                                                                                                                                                                                                   
Comic book                     DEF

Конечно, это в значительной степени зависит от того факта, что ваш текстовый файл будет содержать заголовок и клиент один за другим.

0 голосов
/ 26 февраля 2020

вот еще один способ сделать это. [ ухмылка ] эта использует именованные группы захвата и опции (?ms) многострочные и однострочные движка do tnet regex для разбора блоков текста.

#region >>> fake reading in a text file as one multiline string
#    in real life, use Get-Content -Raw
$InStuff = @'
----------------------------------------
Title: Textbook
Client: ABC
----------------------------------------
----------------------------------------
Title: Comic book
Client: DEF
----------------------------------------
'@
#endregion >>> fake reading in a text file as one multiline string

# split by the lines of hyphens
$SplitInStuff = ($InStuff -split '-{1,}').
    # trim away the unwanted whitespace & non-printing chars
    Trim().
    # remove all the blank lines
    Where({$_})

$Results = foreach ($IS_Item in $SplitInStuff)
    {
    $Null = $IS_Item -match '(?ms)Title: (?<Title>.+)$.*Client: (?<Client>.+)'

    # send the object out to the $Results collection
    [PSCustomObject]@{
        Title = $Matches.Title
        Client = $Matches.Client
        }

    Write-Host ('{0} has been sold to {1}.' -f $Matches.Title, $Matches.Client)
    Write-Host ('=' * 10)
    }

# if you want only the screen display, then you can remove the "$Results = " and the next line
#    the would allow you to use the extracted info - perhaps save it to a CSV file
$Results

вывод ...

Textbook has been sold to ABC.
==========
Comic book has been sold to DEF.
==========

Title       Client
-----       ------
Textbook... ABC   
Comic bo... DEF
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...