将csv列拆分为多个列

时间:2016-04-08 12:58:27

标签: csv powershell outlook

我需要一些帮助,使用powershell将列拆分为CSV文件中的多个列。

这些是Outlook任务完成电子邮件,我们正在收集任务统计信息。我需要从正文栏中提取完成日期和实际工作数据。

这是csv文件的一个条目

Subject,Body,From: (Name)
Task Completed: lprab: 160323-092321 - PCMS:Review/SGCE:Révision,"

Jon York


-----Original Task-----
Subject: lprab: 160323-092321 - PCMS:Review/SGCE:Révision
Priority: Normal

Start date: Wed 2016-03-23
Due date: Wed 2016-03-23

Status: Completed
% Complete: 100%
Date completed: Wed 2016-03-23
Actual work: 15 minutes

Requested by: Internet Content-PAB / Contenu d'Internet-DGAP

------------

","York, Jonathan"

到目前为止,我已设法在此处使用此代码在已完成日期分割身体

ForEach-Object {

    $_.Body,$tempDateCompleted=$_.Body -split "Date completed: ",2
    $_ | Select-Object *,@{Name="DateCompleted";Expression={$tempDateCompleted}}

} #| export-csv

但我之后无法获得实际日期,因为

ForEach-Object {

    $_.Body,$tempDateCompleted=$_.Body -split "Date completed: ",2
    $_ | Select-Object *,@{Name="DateCompleted";Expression={$tempDateCompleted}}

    $_.DateCompleted,$tempActualWork=$_.Body -split "Actual work: ",2
    $_ | Select-Object *,@{Name="ActualWork";Expression={$tempActualWork}}


} #| export-csv

给我这个错误

Property 'DateCompleted' cannot be found on this object; make sure it exists and is settable.
At line:82 char:8
+     $_. <<<< DateCompleted,$tempActualWork=$_.Body -split "Actual work: ",2
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

我的最终目标是获得以下输出

Subject,From,DateCompleted,ActualWork &#34;任务名称&#34;,&#34; Jon York&#34;,&#34; 2016-03-23&#34;,&#34; 15分钟&#34;

谢谢!

3 个答案:

答案 0 :(得分:1)

我很想向您介绍ConvertFrom-StringData,它会将该主体转换为哈希表,然后我们会将其转换为适当的对象供您输出。

 $source = Import-Csv C:\temp\text.csv
 $data = Foreach($row in $source){
    $newHash =  $row.Body -split "`r`n" | Where-Object{$_ -match ":"} | Foreach-object{
        $_ -replace "^(.*?):",'$1='
    } | Out-String |ConvertFrom-StringData

    $newHash.Subject = $row.Subject
    $newHash.From = $row.'From: (Name)'

    New-Object -TypeName pscustomobject -Property $newHash
 } 

这需要$_.Body将其转换为换行符的字符串数组。然后我们过滤掉任何没有“:”的条目。对于每个条目,我们用等号替换第一个冒号(根据ConvertFrom-StringData的要求)。这很好用,因此您不必构建一堆正则表达式模式来匹配您想要的每个属性,从而更容易在输出中添加和删除属性。我们使用原始行中的其他2个条目构建该哈希表。

现在$data包含复杂对象,其中包含条目的所有详细信息。

% Complete     : 100%
Date completed : Wed 2016-03-23
Start date     : Wed 2016-03-23
From           : York, Jonathan
Priority       : Normal
Status         : Completed
Subject        : Task Completed: lprab: 160323-092321 - PCMS:Review/SGCE:Révision
Actual work    : 15 minutes
Due date       : Wed 2016-03-23
Requested by   : Internet Content-PAB / Contenu d'Internet-DGAP

现在你只需要像导出那样处理它。由于某些字段有空格,我们需要引用这些属性。

$data | select Subject,"Date completed","Actual work",From | Export-CSV -NoTypeInformation $path

答案 1 :(得分:0)

_如果您想拉出完成日期,可以使用RegEx模式,如下所示:

$_.body -match 'Date completed:.*\n' | Out-Null;$matches[0] -replace "Date completed: ",""

请注意,当您使用-match时,结果会存储在变量$matches中。在这个例子中,你得到(对于那一行):Wed 2016-03-23

然后你可以在任何你想要的地方分配。它仅在换行符之前选择Date completed:行,然后使用字符串格式化工具删除Date completed位。您可以对其他行使用类似的逻辑,并根据需要进行分配。

修改 您也可以使用lookbehind来避免使用字符串格式,这只会伤到我的头脑,因为我不经常使用它:

$_.body -match '(?<=Date completed: ).*\n' | Out-Null;$matches[0]

编辑2:

由于您已经使用了foreach,因此可以执行以下操作:

#Create a collection you can easily add to
$Results = New-Object System.Collections.ArrayList

#...read the file

ForEach-Object {

    $obj = @{
        Subject = $e.Subject
        From = $_.'From: (Name)'
    }

    if ($_.Body -match '(?<=Actual work: ).*\n') {$obj["Actual Work"] = $matches[0]} 
      else {$obj["Actual Work"] = $null}

    if ($_.Body -match '(?<=Date Completed: ).*\n') {$obj["Date Completed"] = $matches[0]}
      else {$obj["Date Completed"] = $null}

    $Results.Add($Obj) | Out-Null

}

$Results | Export-CSV

您的结果对象看起来像这样:

Name              Value                                                                                        
----              -----                                                                                        
Subject           Task Completed: l...                             
From              York, Jonathan                                                                               
Date Completed    Wed 2016-03-23...                                                                            
Actual Work       15 minutes...   

如果您这样做,请使用ArrayList,这样您就可以添加到集合中而无需每次都完全重建它(因为您的标准@()集合是固定大小的并且必须在每次执行+ =类型添加时将其复制到大小为+ 1的新集合并管道调用以将集合添加到Out-Null以删除输出(您刚刚添加项目的索引)到)。

执行-match时,会得到布尔值true或false响应。如果你将它包装在这样的if / else语句中,你就可以处理如果没有找到结果会发生什么 - 在这种情况下只是将值保留为空。

马特的答案也是一个很好的方式!

答案 2 :(得分:0)

根据每个人给我的信息,它的工作几乎和我希望的一样好。这可能是一个冗长的解决方案,但它运作良好,可预测。

我需要将导入的内容作为输出字符串进行管道处理以使多个正则表达式按预期工作,并再次将字符串作为csv文件管道输出,我需要将其编码为Ascii。

$text = (Get-Content c:\Tools\export.csv) | out-string

$regex = "(?sm),""\s.*?Date completed: "
$replace = ',"'
$output = [regex]::replace($text,$regex,$replace)

$regex = "[\r\n]+Actual work: "
$replace = '","'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm)Requested by:\s.*?"","""
$replace = ',"'
$output = [regex]::replace($output,$regex,$replace)

$regex = '"Mon '
$replace = '"'
$output = [regex]::replace($output,$regex,$replace)

$regex = '"Tue '
$replace = '"'
$output = [regex]::replace($output,$regex,$replace)

$regex = '"Wed '
$replace = '"'
$output = [regex]::replace($output,$regex,$replace)

$regex = '"Thu '
$replace = '"'
$output = [regex]::replace($output,$regex,$replace)

$regex = '"Fri '
$replace = '"'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm) minute(.)\s.*?,"""
$replace = '","minute","'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm) hour(.)\s.*?,"""
$replace = '","hour","'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm) day(.)\s.*?,"""
$replace = '","day","'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm) week(.)\s.*?,"""
$replace = '","week","'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm),""\/O=CO\S.*?"",,""Normal"""
$replace = ''
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm)""Task Declined\S.*?""Task"
$replace = '"Task'
$output = [regex]::replace($output,$regex,$replace)

$regex = "(?sm)""Subject\S.*?Sensitivity"""
$replace = '"Subject","Date Completed","Time","Factor","Developper"'
$output = [regex]::replace($output,$regex,$replace)

$output | Out-file c:\Tools\output.csv -Encoding ascii

现在csv文件中的示例条目如下所示

"Subject","Date Completed","Time","Factor","Developper"
"Task Completed: lprab: 160323-092321 - PCMS:Review/SGCE:R?vision","2016-03-23","15","minute","York, Jonathan"