PowerShell删除或跳过CSV中的列

PowerShell删除或跳过CSV中的列,powershell,csv,Powershell,Csv,首先:我是一名PowerShell新手。我几乎没有使用PowerShell修改或更改CSV文件的经验 我们的系统提供了一种不常见的CSV格式,如下所示: Example1;例2;名称姓氏;例1的内容;例2的内容;厕所;能源部 标题位于信息前面的每一行上。我想去掉一些列,比如Example1和Example2 作为第二步,我需要分配一个新的标题 -标题名、姓氏、地址、电话等 我感谢所有的tipp:-)根据定义,这种模式会导致偶数个“;”分隔的元素。您可以通过算术方式将属性指定给对象,然后将其重新发

首先:我是一名PowerShell新手。我几乎没有使用PowerShell修改或更改CSV文件的经验

我们的系统提供了一种不常见的CSV格式,如下所示:

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]
。如果文件发生更改。。。