我需要根据Col03中的值
在Col01中应用一些更改Col01,Col02,Col03
empty,empty,6
empty,empty,19
empty,empty,75
empty,empty,87
empty,red,145
empty,empty,625
empty,empty,abc
将Col01中的内容设为:
结果:
Col01,Col02,Col03
small,empty,6
small,empty,19
medium,empty,75
medium,empty,87
large,empty,145
large,empty,625
text,empty,abc
答案 0 :(得分:0)
这是对的吗?有多种方法可以实现这一目标。例如:
#Sample data
$csv = @"
Col01,Col02,Col03
empty,empty,6
empty,empty,19
empty,empty,75
empty,empty,87
empty,red,145
empty,empty,625
empty,empty,abc
"@ | ConvertFrom-Csv
#Uncomment to read from file
#$csv = Import-CSV -Path C:\MyFile.csv
$csv | ForEach-Object {
#Get current Col03 value
$col3 = $_.Col03.Trim()
#Calculate new Col01 value
$val = if($col3 -match '^\d+$') {
#Col03 is integer
if([int]$col3 -le 50) { "small" }
elseif ([int]$col3 -le 100) { "medium" }
else { "large" }
} else { "text" }
#Replace Col01-value
$_.Col01 = $val
#Output modified object
$_
}
或使用开关。此示例还将结果保存到文件中:
$csv = @"
Col01,Col02,Col03
empty,empty,6
empty,empty,19
empty,empty,75
empty,empty,87
empty,red,145
empty,empty,625
empty,empty,abc
"@ | ConvertFrom-Csv
#Uncomment to read from file
#$csv = Import-CSV -Path C:\MyFile.csv
$csv | ForEach-Object {
$_.Col01 = switch($_.Col03.Trim()) {
#Contains non-digit - text
{$_ -match '\D'} { 'text'; break; }
#Number - pick category
{[int]$_ -le 50} { 'small'; break; }
{[int]$_ -le 100} { 'medium'; break; }
{[int]$_ -gt 100} { 'large'; break; }
}
#Output modified object
$_
} | Export-CSV -Path MyOuput.csv -NoTypeInformation
输出:
Col01 Col02 Col03
----- ----- -----
small empty 6
small empty 19
medium empty 75
medium empty 87
large red 145
large empty 625
text empty abc
答案 1 :(得分:0)
它是完美的练习素材,你可以用几种方式写它,它的核心是:
Import-Csv
)。测试文字/数字部分
导出CSV行
Export-Csv
可以与Import-Csv
配对,这样就可以使用'对等'在PowerShell中的方式。在PowerShell术语中,您可以安排它:
Import-Csv | ForEach-Object { process one CSV row at a time } | Export-Csv
(as opposed to:
$foo = import-csv
$bar = @()
foreach ($line in $foo) {
#...
$bar += $line
}
which is workable but ugly and wasteful of memory and CPU and won't scale nicely)
好的,我们已经处理了读/处理/写入部分的结构。现在,您将数字值分配给存储桶。
0-10 11-20 21-30 31-40
\__/ \___/ \___/ \___/
或任何尺寸范围/铲斗条件。
该模式尖叫if/else
或switch
。
所以剩下的部分是,你选择哪一个1. 2. 3.方法,你在哪里以及如何从数字中分割文本,以及如何将数字分配到桶中。
大多数选择都与可读性和偏好有关。
具有开始和结束的桶意味着像start -le $num -and $num -lt end
这样的双重测试,然后两个边缘情况只有一个测试。但是你的三个桶意味着需要一个双重测试,两个需要一个测试。
if ($foo -gt 100)
elseif (51 -lt $foo -and $foo -le 100)
elseif ($foo -lt 50)
看看if / elseif和单/双测试的混搭。但是因为你的桶很好地相互碰撞,你可以使用/误用掉落测试:
if ($foo -gt 100) { big }
if ($foo -le 100) { medium }
if ($foo -le 50 ) { small }
好的,有些人会被分配到“中等”状态。然后小'但这个布局要好看,看看它做了什么,不是吗?
除非你阻止它,否则隐含地发生在switch
中,因此有或没有break
的转换案例可以阻止坠落。
如果您选择首先匹配文本,您可能会使用正则表达式来识别不是数字(向后)的内容,所以我明白了:
Import-Csv .\t.csv | ForEach-Object {
if ($_.Col03 -notmatch '^\d+$')
{
$_.Col01 = 'text'
}
else
{
if ([int]$_.Col03 -gt 100) { $_.Col01 = 'large' }
if ([int]$_.Col03 -le 100) { $_.Col01 = 'medium' }
if ([int]$_.Col03 -le 50) { $_.Col01 = 'small' }
}
$_
} # | Export-Csv out.csv -NoTypeInformation
这是可行的,但是呃。如果您选择首先识别数字,则可以使用相同的正则表达式模式,也可以将.Net框架告诉TryParse
- 将文本作为数字。我明白了:
Import-Csv .\t.csv | ForEach-Object {
[int]$n = 0
if ([int]::TryParse($_.Col03, [ref]$n))
{
if ($n -gt 100) { $_.Col01 = 'large' }
if ($n -le 100) { $_.Col01 = 'medium' }
if ($n -le 50) { $_.Col01 = 'small' }
}
else
{
$_.Col01 = 'text'
}
$_
} # | Export-Csv out.csv -NoTypeInformation
哪个不太漂亮。去寻找一个正则表达式/开关组合,然后我得到:
Import-Csv .\t.csv | ForEach-Object {
switch -regex ($_)
{
{$_.Col03 -notmatch '^\d+$'} { $_.Col01 = 'text' ; break }
{[int]$_.Col03 -gt 100} { $_.Col01 = 'large' }
{[int]$_.Col03 -le 100} { $_.Col01 = 'medium' }
{[int]$_.Col03 -le 50 } { $_.Col01 = 'small' }
}
$_
} # | Export-Csv out.csv -NoTypeInformation
这是相当漂亮的,但部分; break
/ fallthrough只是等待有人在阅读时犯错误。并使用异常处理作为控制流,我得到了这个(由于catch块中$_
的范围问题,我已将其更改为首先将整个文件读入内存):
$Rows = foreach ($Row in Import-Csv .\t.csv)
{
try {
if ([int]$Row.Col03 -gt 100) { $Row.Col01 = 'large' }
if ([int]$Row.Col03 -le 100) { $Row.Col01 = 'medium' }
if ([int]$Row.Col03 -le 50) { $Row.Col01 = 'small' }
} catch {
$row.Col01 = 'text'
}
$row
}
$Rows # | Export-Csv out.csv -NoTypeInformation
但是他们都做了基本相同的事情,我无法想出一个更好的方式来做分组,所以我的所有答案都是完全相同的形状,即使它们完全贯穿不同的代码。
Frode F使用PowerShell分配if
再次以不同的方式工作,但在这种方法中,我不能使用通过桶检查 - 因此他使用if / elseif / if而不是if / if / if。这有点好,可以格式化为:
$row.Col01 = if ( $n -le 50) { 'small' }
elseif ( 51 -lt $n -and $n -le 100) { 'medium' }
elseif (100 -lt $n ) { 'large' }
然后它更清晰,它们是开始/结束范围,实际上是的,我最喜欢Frode的方法,只是没有格式化他如何格式化它,并希望我&#dd; d在写这篇文章之前先阅读他的答案。