CWD中有2个文本文件,a.txt
,b.txt
。从a.txt
开始,我想删除b.txt
中前5个字符不存在的所有行,作为任何行的前5个字符。 (或者,另外说明,只保留a.txt
中的那些行,其前5个字符 出现在b.txt
中,作为任何行的前5个字符。)第5个字符后面的内容到最后一行是无关紧要的。
例如:a.txt
abcde000dsdsddsdsdsdsdsd 0123456xxx kkk xyzxyzxyzfeeeee kkkkkkkkkkk
和b.txt
:
012345aabbcc kkkkkkkhhkkvv nnnnnnn5777nnnn77567
预期结果(a.txt
中的行b.txt
中包含1-5个字符的行:
0123456xxx kkkkkkkkkkk
当我运行代码时,它会给我一个空的results.txt
,但没有错误消息。我缺少什么?
$pattern = "^[5]"
$set1 = Get-Content -Path a.txt
$results = New-Object -TypeName System.Text.StringBuilder
Get-Content -Path b.txt | foreach {
if ($_ -match $pattern) {
[void]$results.AppendLine($_)
}
}
$results.ToString() | Out-File -FilePath .\results.txt -Encoding ascii
答案 0 :(得分:1)
您的代码不起作用,因为您的模式与任何内容都不匹配。正则表达式^[5]
表示“字符串开头的字符'5'(方括号定义character class),而不是”字符串开头的5个字符“。后者将是^.{5}
。此外,您永远不会将a.txt
的内容与b.txt
的内容相匹配。
有几种方法可以做你想做的事:
将b.txt.
的每一行中的前5个字符提取到数组,并将a.txt
的行与该数组进行比较。 Esperento57's answer有点使用这种方法,但需要PowerShell v3或更新版本。适用于所有PowerShell版本的变体可能如下所示:
$pattern = '^(.{5}).*'
$ref = (Get-Content 'b.txt') -match $pattern -replace $pattern, '$1' |
Get-Unique
Get-Content 'a.txt' | Where-Object {
$ref -contains ($_ -replace $pattern, '$1')
} | Set-Content 'results.txt'
由于数组中的查找速度相对较慢且无法很好地扩展(随着数组中元素数量的增加,它们会显着变慢),您也可以将参考值放在hashtable中,这样就可以了做索引查找(明显更快):
$pattern = '^(.{5}).*'
$ref = @{}
(Get-Content 'b.txt') -match $pattern -replace $pattern, '$1' |
ForEach-Object { $ref[$_] = $true }
Get-Content 'a.txt' | Where-Object {
$ref.ContainsKey(($_ -replace $pattern, '$1'))
} | Set-Content 'results.txt'
另一种方法是从b.txt
中提取的子字符串中构建第二个regular expression,并将a.txt
的内容与该表达式进行比较:
$pattern = '^(.{5}).*'
$list = (Get-Content 'b.txt') -match $pattern -replace $pattern, '$1' |
Get-Unique |
ForEach-Object { [regex]::Escape($_) }
$ref = '^({0})' -f ($list -join '|')
(Get-Content 'a.txt') -match $ref | Set-Content 'results.txt'
请注意,这些方法中的每一种都会忽略短于5个字符的行。
答案 1 :(得分:0)
尝试这样的事情:
{{1}}
答案 2 :(得分:0)
如果需要考虑性能,请考虑使用散列表作为索引:
$Pattern = '^(.{5}).*'
$a = @{}; $b = @{}
Get-Content -Path a.txt | Where {$_ -Match $Pattern} | ForEach {$a[$Matches[1]] = @($a[$Matches[1]] + $_)}
Get-Content -Path b.txt | Where {$_ -Match $Pattern} | ForEach {$b[$Matches[1]] = @($b[$Matches[1]] + $_)}
$a.Keys | Where {$b.Keys -Contains $_} | ForEach {$a.$_} | Set-Content results.txt