PowerShell删除或跳过CSV中的列
首先:我是一名PowerShell新手。我几乎没有使用PowerShell修改或更改CSV文件的经验 我们的系统提供了一种不常见的CSV格式,如下所示:PowerShell删除或跳过CSV中的列,powershell,csv,Powershell,Csv,首先:我是一名PowerShell新手。我几乎没有使用PowerShell修改或更改CSV文件的经验 我们的系统提供了一种不常见的CSV格式,如下所示: Example1;例2;名称姓氏;例1的内容;例2的内容;厕所;能源部 标题位于信息前面的每一行上。我想去掉一些列,比如Example1和Example2 作为第二步,我需要分配一个新的标题 -标题名、姓氏、地址、电话等 我感谢所有的tipp:-)根据定义,这种模式会导致偶数个“;”分隔的元素。您可以通过算术方式将属性指定给对象,然后将其重新发
Example1;例2;名称姓氏;例1的内容;例2的内容;厕所;能源部
标题位于信息前面的每一行上。我想去掉一些列,比如Example1和Example2
作为第二步,我需要分配一个新的标题
-标题名、姓氏、地址、电话等
我感谢所有的tipp:-)根据定义,这种模式会导致偶数个“;”分隔的元素。您可以通过算术方式将属性指定给对象,然后将其重新发送到新的CSV文件中,从而利用这一点
可能看起来像:
Get-Content C:\Temp\InitialCSVFile.csv |
ForEach-Object{
$TempArr = $_.Split( ';' )
$TempHash = [Ordered]@{}
For($i = 0; $i -lt ($TempArr.Count / 2); ++$i)
{
$TempHash[ $TempArr[ $i ] ] = $TempArr[ $i+4 ]
}
[PSCustomObject]$TempHash
} |
Export-CSV -path C:\Temp\TestCSV.csv -NoTypeInformation -Append -Delimiter ';'
Example1 Example2 Name Lastname
-------- -------- ---- --------
ContentOfExample1 ContentOfExample2 John Doe
ContentOfExample1 ContentOfExample2 John Doe
代码以普通字符串的形式读取文件内容,而不是像CSV那样的半结构化格式。当每一行都通过管道传输到每个对象时,.Split()
字符串方法正在创建一个数组($-Split';'
)。我们实例化一个Hash/Dictionary对象来保存一些键值对。完成后,将使用传统的For循环来引用kay名称和值。名称为元素0,因此其值应为0+4。注意:循环编码为在阵列的中点停止。这就是为什么我前面提到的偶数元素很重要
散列表完成后,代码将其强制转换为[PSCustomObject]
,并通过管道将其发送到导出CSV
,后者当然处理对象。这将产生一个新的CSV文件,看起来像:
Get-Content C:\Temp\InitialCSVFile.csv |
ForEach-Object{
$TempArr = $_.Split( ';' )
$TempHash = [Ordered]@{}
For($i = 0; $i -lt ($TempArr.Count / 2); ++$i)
{
$TempHash[ $TempArr[ $i ] ] = $TempArr[ $i+4 ]
}
[PSCustomObject]$TempHash
} |
Export-CSV -path C:\Temp\TestCSV.csv -NoTypeInformation -Append -Delimiter ';'
Example1 Example2 Name Lastname
-------- -------- ---- --------
ContentOfExample1 ContentOfExample2 John Doe
ContentOfExample1 ContentOfExample2 John Doe
注意:显然数据是多余的,因为我刚刚重复了您的
输入文件中的示例。这不应该是你生活中的问题
数据
注意:可能不需要重复重新创建$TempHash
,因为我们将
在每个循环内部迭代中重新分配每个键的值。现在
我将让这个例子保持原样
更新:要排除属性:
$ExcludeProperties = @( 'Example1', 'Example2' )
Get-Content C:\Temp\InitialCSVFile.csv |
ForEach-Object{
$TempArr = $_.Split( ';' )
$TempHash = [Ordered]@{}
For($i = 0; $i -lt ($TempArr.Count / 2); ++$i)
{
$TempHash[ $TempArr[ $i ] ] = $TempArr[ $i+4 ]
}
[PSCustomObject]$TempHash
} |
Select-Object -Property * -ExcludeProperty $ExcludeProperties |
Export-CSV -path C:\Temp\TestCSV.csv -NoTypeInformation -Append -Delimiter ';'
一种输出CSV的奇怪方式
您可以做的是将第一行拆分为分隔符代码>以获取每列的标题
一旦你做到了这一点,剩下的就不难做到了:
$csv = Get-Content -Path 'D:\Test\blah.csv' | Where-Object {$_ -match '\S'}
$parts = $csv[0] -split ';'
# calculate the number of parts that make up the headers
[int]$numberOfHeaders = $parts.Count / 2
# join the headers into a string
$header = $parts[0..($numberOfHeaders - 1)] -join ';'
# cut off the headers from every line
$rows = foreach ($line in $csv) { $line.Substring($header.Length + 1) }
# convert to an array of objects, skip the first two columns and export to a new file
$header, $rows | ConvertFrom-Csv -Delimiter ';' |
Select-Object * -ExcludeProperty $parts[0..1] |
Export-Csv -Path 'D:\Test\blah2.csv' -Delimiter ';' -NoTypeInformation
假设列的数量可能是随机的,并且要排除的属性是已知的,则可以执行以下操作将数据解析为自定义对象:
Get-Content file.csv | Foreach-Object {
$count = 0 # Tracks column counts to split the row evenly
$cols = $_ -split ';'
# $headers gets the first half of the columns. $data gets the remainder.
$headers,$data = $cols.where({$count++ -lt $cols.count/2},'Split')
# Uses calculated properties to add your new properties. You will need to fill in your own logic since you provided none here.
($headers -join ';'),($data -join ';') | ConvertFrom-Csv -Delimiter ';' |
Select-Object *,@{n='Address';e={'Electric Avenue'}},@{n='Phone';e={'867-5309'}} -exclude example1,example2
}
如果csv文件中的所有数据都包含相同的标题,您可以使用导出csv
从数据创建正确的csv:
Get-Content file.csv | Foreach-Object {
$count = 0 # Tracks column counts to split the row evenly
$cols = $_ -split ';'
$headers,$data = $cols.where({$count++ -lt $cols.count/2},'Split')
($headers -join ';'),($data -join ';') | ConvertFrom-Csv -Delimiter ';' |
Select-Object *,@{n='Address';e={'Electric Avenue'}},@{n='Phone';e={'867-5309'}} -exclude example1,example2
} | Export-Csv output.csv -NoType
如果每一行可以有不同数量的列,则每行可能需要一个CSV文件,除非您解析所有数据并确定所有可能的列名。如果希望保持与源相同的格式,但只希望操作列和数据,可以执行以下操作,这将适用于不同数量的列:
Get-Content file.csv | Foreach-Object {
$count = 0 # Tracks column counts to split the row evenly
$cols = $_ -split ';'
$headers,$data = $cols.where({$count++ -lt $cols.count/2},'Split')
$newObj = ($headers -join ';'),($data -join ';') | ConvertFrom-Csv -Delimiter ';' |
Select-Object *,@{n='Address';e={'Electric Avenue'}},@{n='Phone';e={'867-5309'}} -exclude example1,example2
"{0};{1}" -f ($newObj.psobject.properties.name -join ';'),($newObj.psobject.properties.value -join ';')
}
CSV文件中引用的标题和值是否是典型的?是否希望保留当前格式(每行都有这些“内联标题”)?谢谢!我决不会想到那样做。我会用原始文件测试这个。只是为了澄清,[$i+4]4是标题的列数,对吗?这对我的帮助很大。是的,从[0+4]开始就是[4]。注意:您可以通过将其存储在变量中来与其他一些示例组合。这可能有助于使其更易于维护,并且可能看起来像:$Offset=$TempArr.count/2
然后[$i+$Offset]
。如果文件发生更改。。。