【问题标题】:Powershell copy a column from a csv file and paste into the first row of another csv filePowershell 从 csv 文件复制一列并粘贴到另一个 csv 文件的第一行
【发布时间】:2021-06-29 18:51:09
【问题描述】:

我有一个名为“final results.csv”的 csv 文件,有一个标题行和一些数据。标题数据是带下划线的“别名”,例如 User_Name、User_Age、User_firstN、User_LastN

我有另一个名为“header names.csv”的 csv 文件,其中存储了标题的实际名称。它只有一列,因此数据如下所示。

Header
User Name
User Age
First Name
Last Name

目标是从第二个文件中提取标题实际名称,并将它们粘贴到第一个文件的第一行。所以第一个文件(“final results.csv”)有一个带有实际标题名称而不是别名的标题。

如何使用 Powershell 实现这一目标?提前致谢!

【问题讨论】:

  • 列在 CSV 中的水平位置顺序是否与它们在文本文件中的垂直位置顺序相同?并且所有列名 only 都用空格替换下划线吗?如果是后者,有一种更简单的方法可以做到这一点——我会在看到你的回复后举一个例子。
  • 顺序相同。名称不一定与没有下划线的别名相同。

标签: powershell csv


【解决方案1】:

如果我理解正确,您有一个包含要替换的标题名称的 CSV。目前它们是X_X,您想用X X 替换它们。您可以使用Select-Object 和计算属性轻松完成此操作。现在,如果您有很多标题,那可能需要大量的手动工作。这是一种获取标头并动态构建计算属性的方法。

演示数据。

# first file
$csv = @"
User_Name,User_Age,First_Name,Last_Name
ab,20,a,b
cd,21,c,d
ef,22,e,f
"@ |ConvertFrom-Csv

# second file
$headers = @"
header
User Name
User Age
First Name
Last Name
"@ | ConvertFrom-Csv

构建计算属性

$SelectProps = @($headers | ForEach-Object {
    @{n=$_.header;e={$($_.header.Replace('_',' '))}}
})

现在应该是这样的

Name                           Value                                                                                                                                                          
----                           -----                                                                                                                                                          
n                              User Name                                                                                                                                                      
e                              User_Name                                                                                                                                                      
n                              User Age                                                                                                                                                       
e                              User_Age                                                                                                                                                       
n                              First Name                                                                                                                                                     
e                              First_Name                                                                                                                                                     
n                              Last Name                                                                                                                                                      
e                              Last_Name  

现在我们只需替换它们。

$csv | Select-Object $SelectProps

User Name User Age First Name Last Name
--------- -------- ---------- ---------
ab        20       a          b        
cd        21       c          d        
ef        22       e          f       

编写代码

$csv = Import-Csv "final results.csv"

$headers = Import-Csv "header names.csv"

$SelectProps =  @($headers | ForEach-Object {
    @{n=$_.header;e=($_.header.Replace(' ','_'))}
})

$csv | Select-Object $SelectProps |
    Export-Csv -Path "final results.csv" -NoTypeInformation

但您也可以将第一行替换为Get-ContentSet-Content-join

$headers = Import-Csv "header names.csv"

Set-Content -Value $(
    $headers.header -join ','
    Get-Content "final results.csv" | Select-Object -Skip 1
) "final results.csv"

Import-Csv "final results.csv"

User Name User Age First Name Last Name
--------- -------- ---------- ---------
ab        20       a          b
cd        21       c          d
ef        22       e          f

【讨论】:

  • 谢谢道格。我接受了另一个更短的解决方案。但这看起来不错,我绝对可以将它用于其他场景。
  • 没问题。也许我应该采用第二种解决方案。并不是 100% 清楚列与标题的顺序相同,所以我专注于一个解决方案,不管它们的顺序是什么。祝你有美好的一天
  • 谢谢,我看到你也有更短的版本。我认为您的解决方案可能会帮助更多的人,因为我意识到即使对我来说订单并不总是相同,所以这个解决方案更有帮助,我需要根据您提供的这个来找出我的代码。谢谢!
  • 刚刚尝试过我的代码,我有一个更新的头文件,在两个单独的列中包含字段名称和字段别名作为映射文件,您的解决方案非常完美!!!我只需要更新这个 @{n=$_.name;e=($_.alias)} 因为我有映射。再次感谢!!!
  • 很高兴我能帮上忙。
【解决方案2】:

如果是我,我不会费心阅读 CSV,我只会将其作为文本处理。您真正要做的就是用正确的标题替换第一行。假设文件不比下面描述的更复杂,应该可以工作:

# Get the headers:
$Headers = (Get-Content <2ndFile> | Select-Object -Skip 1) -join ','

# Combine with the CSV file skip the first row to accomplish the replace:
$Headers, @(Get-Content <1stFile> | Select-Object -Skip 1) | Set-Content <NewCsv>

显然,根据需要调整文件名...

【讨论】:

  • 谢谢!这就像一个魅力,如此简短,伟大的解决方案!我看到你修复了 ),我打算添加它但不得不退出。
  • 谢谢,但我很困惑。为什么标题的顺序不同。至少如前所述,依靠字符串替换不能满足问题。即“First Name”映射到“User_FirstN”而不是“First_Name”,因为在其他解决方案中隐含并有效地硬编码。也就是说,如果不摄取 CSV 数据作为对象,这可能几乎一样短。我可能只是创建一个哈希来解析/关联一个版本的标头与另一个版本。如果有一个可靠的假设,除了下划线之外,标题是相同的,我仍然可以认为简洁雄辩的解决方案......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 2021-02-26
  • 2022-01-04
  • 1970-01-01
  • 2020-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多