我试图编写一个代码,根据第8列中存储的文本字符串删除特定日期之前的所有行(日期存储在第1列中)。我的文本文件非常大(超过80万)行)所以我不确定我的代码是否是最好的方法。到目前为止,我的代码只是在$ date1之前删除所有行。
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$header="Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8" | Out-File test.txt -encoding "Default"
get-content .\bigfile.txt |select -Skip 1 | where { [datetime]($_.split(','))[0] -ge $date1} | Out-File test.txt -encoding "Default" -append
因此对于第8列中的文本字符串,其中最后3个字符是" -XX"或" .YY"应删除$ date1之前的所有行。对于第8列中的文本字符串,其中最后3个字符不是" -XX"或" .YY" ,应删除$ date2之前的所有行。 我真的希望我的描述足够清楚。如果不是,我很抱歉。
请参阅下面的测试文件: bigfile.txt
Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8
8/14/2014,11.4,11.4,11.07,11.11,52930,0,Text1
8/15/2014,11.18,11.18,10.78,10.81,80517,0,Text1
8/18/2014,10.92,11.12,10.81,11,188671,0,Text1
8/14/2014,11.09,11.79,11.036,11.49,142205,0,Text2-XX
8/15/2014,11.43,11.738,11.32,11.7,70846,0,Text2-XX
8/16/2014,11.67,12.56,11.458,12.42,170739,0,Text2-XX
8/17/2014,12.47,12.79,12.22,12.66,176367,0,Text2-XX
8/14/2014,12.7,13.5,12.6,13.26,411410,0,Text3
8/15/2014,13.35,13.62,13.17,13.55,209561,0,Text3
8/16/2014,13.55,13.57,13.28,13.49,104880,0,Text3
8/14/2014,13.4,13.61,13.14,13.18,167355,0,Text4.YY
8/15/2014,13.17,13.17,12.67,13.04,119659,0,Text4.YY
8/16/2014,13.07,13.07,12.64,12.73,133181,0,Text4.YY
8/15/2014,12.75,13.43,12.75,13.38,154302,0,Text5
8/16/2014,13.43,13.78,13.28,13.49,203535,0,Text5
8/17/2014,13.43,14.29,13.38,14.24,167803,0,Text5
8/18/2014,14.26,14.53,13.79,13.91,124665,0,Text5
8/19/2014,13.87,13.95,13.25,13.3,123747,0,Text5
8/20/2014,13.27,13.45,12.79,12.94,128408,0,Text5
8/21/2014,12.81,13.22,12.81,13.1,74911,0,Text5
8/15/2014,13.09,13.26,12.81,13.01,204025,0,Text5.YY
8/16/2014,13.07,13.07,12.58,12.64,75625,0,Text5.YY
8/17/2014,12.52,13.26,12.52,13.26,115968,0,Text5.YY
答案 0 :(得分:1)
这是一个简单的Import-CSV
,一个Where
语句,使用分组,RegEx匹配,分组中的-and
条件以及它们之间的-or
条件。类似的东西:
Import-CSV .\bigfile.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
Export-Csv test.txt -NoTypeInformation -append
编辑:Matt指出我的日期比较逻辑是有缺陷的,因为它考虑了文件中的文字字符串。我更新了我的代码以解决这个问题。
话虽如此,请为了上帝的爱,请使用Matt的答案!我没有看到文件中有800,000行需要更新。我的答案应该可以正常工作,但它会非常缓慢,因为它会将整个文件转换为一个对象数组,解析它们,然后立即将它们全部写回来。我离开答案是因为它功能齐全,但更适合较小的文件。
编辑2:好吧,如果您没有看到Matt代码的性能提升(您可能希望在其代码中将ReadCount更改为1000或2000),请点击此处#39;我的更新代码将在将其写回文件之前删除多余的引号。
(Import-CSV C:\temp\new.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
ConvertTo-Csv -NoTypeInformation) -replace '"'|
set-content $output
答案 1 :(得分:1)
我希望在拥有1000行数据的情况下,这可能会表现得更好。唯一的规定是您应该手动从文件中删除第一行数据,因为此方法以块的形式读取行并且每行都有一个if语句来检查标题似乎是浪费
$output = C:\temp\test.txt
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
Set-Content -Path $output -Value "Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8"
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
} | Add-Content $output
我发誓我并没有偷走Mads的逻辑。
标题帐户
我无法通过使用if
语句提出一种聪明的方法来处理标头期望。 不应在处理时间上添加太多。
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
If($_ -notmatch "header"){
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
}
} | Add-Content $output
答案 2 :(得分:1)
我知道这已被回答,但看起来很有趣。此外,此方法可能会提供更好的性能。我使用IO.StreamReader逐行获取文件和解析,并使用IO.StreamWrite立即输出结果。我还没有验证条件..
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$filePath = "path\to\bigfile.txt"
$outputfile = "outfile.txt"
$file = New-Object System.IO.StreamReader -Arg "$filePath"
$outFile = New-Object System.IO.StreamWriter -arg "$outputfile"
while ($line = $file.ReadLine()) {
$line | % {
$items = $_.Split(',')
try{
[datetime]$rowDate = $items[0]
[string]$Header8 = $items[-1]
If($rowDate -le $date1 -and $Header8 -match "-XX|.YY")
{$null}
ElseIf($rowDate-le $date2 -and $Header8 -notmatch "-XX|.YY")
{$null}
Else {
$outItem = $items -join ","
$outFile.WriteLine($outItem)}
}
catch [System.Exception] {$null}
}
}
$file.close()
$outFile.Close()