2014-02-10 3 views
1

У меня есть (надеюсь) быстрый вопрос, который я, похоже, не могу решить самостоятельно.Powershell: Splitting String в CSV

У меня есть строка:

ITEM1 Количество: 12x 355ml bottlePrice: $ 23,95 $ 23,50 SAVE $ 0,45

То, что я хотел бы разделить, и вставить в файл CSV. Столбцы в сгенерированном CSV, и их значения, будут:

Имя: (все до «Количество:». В строке выше)

Количество: (между количеством и х)

Размер: (все между й и бутылкой)

OrigPrice: (все после того, как цена и вторым знак $)

SalePrice: (все между OrigPrice и SAVE)

Экономия: (все после того, как "SAVE")

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

Я ценю помощь!

ответ

2

Как о чем-то вроде:

$subject = 'ITEM1 Quantity: 12x 355ml bottlePrice: $23.95 $23.50 SAVE $0.45' 

if ($subject -cmatch '^(?<Name>.*)Quantity:(?<Quantity>.*)x(?<Size>.*)bottle\s*Price:(?<OrigPrice>.*)\s*(?<SalePrice>\$.*)SAVE(?<Savings>.*)$') { 
    $result = $matches[0] 
} else { 
    $result = '' 
} 

"Matches:" 
$matches 

Я не мог сказать, если там действительно должно было быть пространство между бутылкой & Цена (это не похоже на это, но это будет обрабатывать его, если является).

Если вам нужно имя, вы можете обращаться к нему как:

$matches["Name"] 

А лучшее решение (и тот, который фактически получает его в формат CSV, будет что-то вроде следующего (благодаря @nickptrvc для указания из того, что я пропустил):

function Read-Data { 
[cmdletbinding()] 
    param(
     [parameter(Mandatory)][string]$Path 
    ) 

    $reader = [System.IO.File]::OpenText($Path) 

    while(($subject = $reader.ReadLine()) -ne $null) { 
     if ($subject -cmatch '^(?<Name>.*)Quantity:(?<Quantity>.*)x(?<Size>.*)bottle\s*Price:(?<OrigPrice>.*)\s*(?<SalePrice>\$.*)SAVE(?<Savings>.*)$') { 
      $result = $matches[0] 
      $obj = [PSCustomObject]@{ 
       Name=$matches["Name"].trim(); 
       Quantity=$matches["Quantity"].trim(); 
       Size=$matches["Size"].trim(); 
       OrigPrice=$matches["OrigPrice"].Trim(); 
       SalePrice=$matches["SalePrice"].Trim(); 
       Savings=$matches["Savings"].Trim() 
      } 
      $obj 
     } 
    } 
} 

затем, чтобы использовать его, сохранить это в файл (я назвал мое чтение Data.ps1), подключим файл, а затем у вас есть два варианта: 1) вы можете используйте ConvertTo-Csv, чтобы просто преобразовать объекты в CSV и вернуть результат на экран, или лет и можно использовать Export-Csv, чтобы сохранить его в файл:

. C:\Test\Convert-Data.ps1 
Read-Data -Path C:\Test\datafile.dat | ConvertTo-Csv -NoTypeInformation 

или

Read-Data -Path C:\Test\datafile.dat | Export-Csv -NoTypeInformation -Path C:\Test\datafile.csv 
+1

Чтобы получить результат, CSV, вы можете добавить это в истинном объеме КРП блока. Порядок будет алфавитным по именам ключей, которые являются именами групп регулярных выражений в этом случае, например. Имя, количество и т. Д. 'if (...) { $ matches.remove (0) $ result = ($ matches.values ​​|% {$ _.trim()}) -join ',' } else { ... } ' – nickptrvc

+1

Спасибо @nickptrvc, я получил такое впечатление от регулярного выражения, что забыл ответить на остальную часть вопроса ... :) Я обновил свой ответ с функцией, которая возвращает объект, подходящий для Export-Csv и ConvertTo-Csv ... –

+1

Я тоже был впечатлен регулярным выражением! Я скажу, что я предложил фрагмент, потому что он не требует, чтобы пользователь вводил имена ключей, такие как $ matches ['Size'], делая его несколько более динамичным (ограничение, конечно, регулярным выражением). Мне определенно понравилась идея типа PSCustomObject, но пользователь должен использовать версию 3 для создания этих типов. В версии 2 использование PSObject происходит очень медленно. Поэтому в этом случае я обычно по умолчанию использую хеш-таблицу и конкатенацию строк. Самое большое преимущество - обратная совместимость от 3 до 2. – nickptrvc