Powershell 将导入的 CSV 导出为没有分隔符的固定记录长度?
Powershell export an imported CSV as fixed record length with no delimiter?
我有一个非常标准的 CSV 文件,它看起来像这样:
heading1,heading2,heading3
aaaaaaaaa,bb,ccccccc
d,eeeeeeee,ff
gggggggg,hh,iiiiiiiiiii
此文件已使用 import-csv 导入到 object。我现在想将 object 导出到一个具有固定记录长度且没有定界符且没有 table headers 的文件。如果导入的值对于固定文件来说太长,则应将其截断。如果导入的值太短,值应该左对齐并用空格填充。
假设宽度为:
heading1 is 5
heading2 is 2
heading3 is 10
基本上输出应该是这样的:
aaaaabbccccccc
d eeff
ggggghhiiiiiiiiii
请注意第 3 列中值末尾的空格。
算法应该不会完全低效 - 它将用于转换 300MB 的 csv 文件。
我在 Whosebug 上搜索并用谷歌搜索了一段时间,可以使用自定义 table 格式和 format-table 等解决方案找到一些相关问题,但这些解决方案似乎并不容易适应table 对我来说这个具体问题。
至于原因:这种非常 ugly/unusual 的格式是小众 COTS 软件所必需的。
我真的不知道你为什么要这样做,但嘿,你这样做很公平。
我想我明白你想做什么,这会给你一个数组,每一行都是将数据处理成你想要的格式,然后你可以将该数组循环到 txt 文件、日志文件等你要。
$spacerCSVFile = "spacers.csv"
$prinspacerCSV = Import-Csv $spacerCSVFile -header "1","2","3"
$processedArray = New-Object System.Collections.Generic.List[System.Object]
foreach($row in $prinspacerCSV) {
if ($row.1 -like "heading*") {
# do nothing for headings
} else {
$item1 = $row.1
$item2 = $row.2
$item3 = $row.3
while ($item1.length -lt 6) {
$item1 += " "
}
while ($item2.length -lt 3) {
$item2 += " "
}
while ($item3.length -lt 11) {
$item3 += " "
}
if ($item1.length -gt 5) {
$item1 = $item1.substring(0,5)
}
if ($item2.length -gt 2) {
$item2 = $item2.substring(0,2)
}
if ($item3.length -gt 10) {
$item3 = $item3.substring(0,10)
}
$processedArray += ,"$item1$item2$item3"
}
}
foreach ($item in $processedArray) {
write-host $item
}
不过,我建议您值得一试,先准备好一些代码,因为堆栈溢出的想法是帮助您的代码,而不是提供它。
这非常丑陋,可能比它需要的更复杂,但据我所知这是可行的。
希望这能给你一个想法或者这只是帮助
$file = "C:\Logs\Test.csv"
$data = Import-Csv $file
$properties = $data |
Get-Member |
Where-Object MemberType -EQ NoteProperty |
Select Name
foreach ($line in $data){
[string]$dataout = $null
foreach ($property in $properties) {
$dataout = $dataout + $line.($property.Name)
}
if($dataout.Length -eq 20){
$dataout
}
elseif ($dataout.Length -lt 20) {
Do{
$dataout = $dataout + " "
}
Until($dataout.Length -eq 20)
$dataout
}
else {
$dataout = ($dataout.Substring(0,20))
$dataout
}
}
## Q:\Test18\SO_51265871.ps1
$SPC = ' ';
Import-Csv .\Input.csv |
ForEach-Object {"[{0}{1}{2}]" -f ($_.heading1+$SPC).Substring(0,5),
($_.heading2+$SPC).Substring(0,2),
($_.heading3+$SPC).Substring(0,10)
} | Set-Content .\Output.rec
格式字符串中的[]
只是为了显示包含尾随空格的长度。
示例输出:
PS> Get-Content .\Output.rec
[aaaaabbccccccc ]
[d eeff ]
[ggggghhiiiiiiiiii]
编辑:一个更通用的变体,从数组馈送列宽 - 相同的输出
$CW = @(5,2,10) # array CW = ColumnWidth
Import-Csv .\Input.csv | ForEach-Object { $i = 0
"[{0}{1}{2}]" -f `
($_.heading1).PadRight($CW[$i]).Substring(0,$CW[$i++]),
($_.heading2).PadRight($CW[$i]).Substring(0,$CW[$i++]),
($_.heading3).PadRight($CW[$i]).Substring(0,$CW[$i])
} #| Set-Content .\Output.rec
我有一个非常标准的 CSV 文件,它看起来像这样:
heading1,heading2,heading3
aaaaaaaaa,bb,ccccccc
d,eeeeeeee,ff
gggggggg,hh,iiiiiiiiiii
此文件已使用 import-csv 导入到 object。我现在想将 object 导出到一个具有固定记录长度且没有定界符且没有 table headers 的文件。如果导入的值对于固定文件来说太长,则应将其截断。如果导入的值太短,值应该左对齐并用空格填充。
假设宽度为:
heading1 is 5
heading2 is 2
heading3 is 10
基本上输出应该是这样的:
aaaaabbccccccc
d eeff
ggggghhiiiiiiiiii
请注意第 3 列中值末尾的空格。
算法应该不会完全低效 - 它将用于转换 300MB 的 csv 文件。
我在 Whosebug 上搜索并用谷歌搜索了一段时间,可以使用自定义 table 格式和 format-table 等解决方案找到一些相关问题,但这些解决方案似乎并不容易适应table 对我来说这个具体问题。
至于原因:这种非常 ugly/unusual 的格式是小众 COTS 软件所必需的。
我真的不知道你为什么要这样做,但嘿,你这样做很公平。
我想我明白你想做什么,这会给你一个数组,每一行都是将数据处理成你想要的格式,然后你可以将该数组循环到 txt 文件、日志文件等你要。
$spacerCSVFile = "spacers.csv"
$prinspacerCSV = Import-Csv $spacerCSVFile -header "1","2","3"
$processedArray = New-Object System.Collections.Generic.List[System.Object]
foreach($row in $prinspacerCSV) {
if ($row.1 -like "heading*") {
# do nothing for headings
} else {
$item1 = $row.1
$item2 = $row.2
$item3 = $row.3
while ($item1.length -lt 6) {
$item1 += " "
}
while ($item2.length -lt 3) {
$item2 += " "
}
while ($item3.length -lt 11) {
$item3 += " "
}
if ($item1.length -gt 5) {
$item1 = $item1.substring(0,5)
}
if ($item2.length -gt 2) {
$item2 = $item2.substring(0,2)
}
if ($item3.length -gt 10) {
$item3 = $item3.substring(0,10)
}
$processedArray += ,"$item1$item2$item3"
}
}
foreach ($item in $processedArray) {
write-host $item
}
不过,我建议您值得一试,先准备好一些代码,因为堆栈溢出的想法是帮助您的代码,而不是提供它。
这非常丑陋,可能比它需要的更复杂,但据我所知这是可行的。
希望这能给你一个想法或者这只是帮助
$file = "C:\Logs\Test.csv"
$data = Import-Csv $file
$properties = $data |
Get-Member |
Where-Object MemberType -EQ NoteProperty |
Select Name
foreach ($line in $data){
[string]$dataout = $null
foreach ($property in $properties) {
$dataout = $dataout + $line.($property.Name)
}
if($dataout.Length -eq 20){
$dataout
}
elseif ($dataout.Length -lt 20) {
Do{
$dataout = $dataout + " "
}
Until($dataout.Length -eq 20)
$dataout
}
else {
$dataout = ($dataout.Substring(0,20))
$dataout
}
}
## Q:\Test18\SO_51265871.ps1
$SPC = ' ';
Import-Csv .\Input.csv |
ForEach-Object {"[{0}{1}{2}]" -f ($_.heading1+$SPC).Substring(0,5),
($_.heading2+$SPC).Substring(0,2),
($_.heading3+$SPC).Substring(0,10)
} | Set-Content .\Output.rec
格式字符串中的[]
只是为了显示包含尾随空格的长度。
示例输出:
PS> Get-Content .\Output.rec
[aaaaabbccccccc ]
[d eeff ]
[ggggghhiiiiiiiiii]
编辑:一个更通用的变体,从数组馈送列宽 - 相同的输出
$CW = @(5,2,10) # array CW = ColumnWidth
Import-Csv .\Input.csv | ForEach-Object { $i = 0
"[{0}{1}{2}]" -f `
($_.heading1).PadRight($CW[$i]).Substring(0,$CW[$i++]),
($_.heading2).PadRight($CW[$i]).Substring(0,$CW[$i++]),
($_.heading3).PadRight($CW[$i]).Substring(0,$CW[$i])
} #| Set-Content .\Output.rec