【问题标题】:Reformat column names in a csv with PowerShell使用 PowerShell 重新格式化 csv 中的列名
【发布时间】:2015-08-17 17:04:54
【问题描述】:

问题

如何在维护数据的同时根据公式或子例程重新格式化未知的 CSV 列名(例如,通过运行修剪或正则表达式或其他方式将列 " Arbitrary Column Name " 重命名为 "Arbitrary Column Name")?

目标

我正在尝试或多或少地清理需要由现有 PowerShell 脚本处理的手工制作(或至少手工编辑)的 csv 文件中的列(名称)。在这种特定情况下,列中的空格可以通过调用[String]::Trim() 删除,或者可以使用适当的正则表达式忽略,但我无法在导入或处理时找到调用或使用这些技术的方法CSV。

短背景

过去,大多数文件和列都已正确输入 CSV,但最近在处理过程中删除了一些列;我确定这是因为文件包含一个空格(例如,Select-Object 被告知获取"RFC",但Import-CSV 检索到"RFC ",因此没有匹配匹配)。在这种情况下,告诉客户手动正确输入(虽然首选且更简单)不是一种选择。

考虑的选项

我可以手动处理文件的文本,但这是一种重新发明轮子的混乱且容易出错的方法。我想知道Select-Object 的语法是否允许对列名进行更柔和的匹配,但我找不到该信息。

我在概念上最接近的是在对Select-Object 的调用中使用计算属性来重命名列,但我只能找到将已知列重命名为另一个已知列的方法。因此,这将需要枚举列并将它们与预期的列名称完全匹配(首选)或更软匹配(例如在修剪或通过正则表达式匹配作为后备之后进行比较),然后创建名称映射集合以用于构造计算的属性从该信息中选择一个新对象。

这似乎可行,但它比我更喜欢它的工作,我不禁希望有一种我无法通过 Google 找到的更简单的方法。也许我应该试试 Bing?

【问题讨论】:

    标签: powershell csv


    【解决方案1】:

    示例文件

    假设你有一个这样的file.csv:

    " RFC "
    "1"
    "2"
    "3"
    

    代码

    现在尝试运行以下命令:

    $CSV = Get-Content file.csv -First 2 | ConvertFrom-Csv
    $FixedHeaders = $CSV.PSObject.Properties.Name.Trim(' ')
    Import-Csv file.csv -Header $FixedHeaders |
        Select-Object -Skip 1 -Property RFC
    

    输出

    你会得到这个输出:

    RFC
    ---
    1  
    2  
    3  
    

    说明

    首先我们使用Get-Content 和参数-First 2 来获取前两行。通过管道连接到ConvertFrom-Csv 将允许我们使用PSObject.Properties.Name 访问标题。使用 Import-Csv 和 -Header 参数来使用修剪后的标题。管道到Select-Object 并使用-Skip 1 跳过原始标题。

    【讨论】:

    • 这看起来像我所希望的(我能想象到的最接近清洁的) - 我将测试并选择它是否像看起来那样工作(尽管我刚刚注意到一些让我想知道的东西)。谢谢! ---- 如果它看起来增加了讨论的任何内容,我也会发布我想出的不太干净但更通用的解决方案
    • 我只是在精神上经历它并扮演魔鬼的拥护者。我想知道:如果某人真的很卑鄙或粗心,并且在一个或多个标题名称中输入了回车符怎么办?我认为Get-Content 不会正确解析...(?)
    • 如果列名中有回车,Get-Content file.csv -First 2 | ConvertFrom-Csv 可能会失败。
    【解决方案2】:

    我不确定在效率方面的比较,但我认为这更硬一些,并且只导入 CSV 一次。您也许可以使用@lahell 的方法和Get-Content -raw,但是这已经完成并且有效,所以我将把它留给社区来确定哪个更好......

    #import the CSV
    $rawCSV = Import-Csv $Path
    
    #get actual header names and map to their reformatted versions
    $CSVColumns = @{}
    $rawCSV | 
        Get-Member | 
        Where-Object {$_.MemberType -eq "NoteProperty"} |
        Select-Object -ExpandProperty Name | 
        Foreach-Object {
    
            #add a mapping to the original from a trimmed and whitespace-reduced version of the original
            $CSVColumns.Add(($_.Trim() -replace '(\s)\s+', '$1'), "$_")
        }
    
    #Create the array of names and calculated properties to pass to Select-Object
    $SelectColumns = @()
    $CSVColumns.GetEnumerator() |
        Foreach-Object {
            $SelectColumns += {
                if ($CSVColumns.values -contains $_.key) {$_.key}
                else { @{Name = $_.key; Expression = $CSVColumns[$_.key]} }
            }
        }
    
    $FormattedCSV = $rawCSV | 
        Select-Object $SelectColumns
    

    这是手动复制到我无权运行它的计算机上,因此可能存在错误 - 我尝试正确复制它

    【讨论】:

      【解决方案3】:

      您可以使用 gocsv https://github.com/DataFoxCo/gocsv 查看 csv 的标头,然后您可以重命名标头、斩首文件、交换列、连接、合并、任意数量的转换

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-15
        • 2016-10-04
        • 1970-01-01
        • 1970-01-01
        • 2020-10-28
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        相关资源
        最近更新 更多