【问题标题】:Powershell remove any lines from big text file containing any of a large number of stringsPowershell 从包含大量字符串的大文本文件中删除任何行
【发布时间】:2023-03-19 19:25:02
【问题描述】:

我们有一个大的 (~100MB) 文本文件。 我们需要删除任何包含某些短语的行。我想用 PowerShell 来代替目前的做法,它使用 windows grep 并且是一个 .bat 文件。

问题是,大约有 95 个关键短语。任何包含这些短语的行都必须删除。

关键短语列表包含在"badPhrases.txt" 中,像常规文本文件一样以行分隔。大概有 100 个,我不想将它们包含在硬编码列表中,但如果必须的话我会。

我尝试了几个/几个比较,但我的输出总是比我的原始输入文件大!或者,0k(空)。我究竟做错了什么?我怀疑问题出在Where-Object 过滤器中,但我可能是错的。

[string[]]$arrayFromFile = Get-Content -Path '.\badPhrases.txt'
get-content ".\inputfile.txt" | Where-Object {$_ -notlike $arrayFromFile} | Out-File ".\clean_data.txt" -Force

我尝试过 -notlike、-notin -notmatch 和 -notcontains(同时以看似合乎逻辑的方式翻转数组和输入对象)。比如……

Where-Object {$arrayFromFile -notin $_}
....
Where-Object {$_ -notcontains $arrayFromFile}
....
Where-Object {$_ -notlike arrayFromFile}

我搜索了 stackOverflow 并四处搜索,但我找不到任何未死的链接,这些链接解决了这个确切的用例。有一个“嘿脚本专家”的引用,但是...链接已失效。

【问题讨论】:

    标签: arrays regex powershell data-processing


    【解决方案1】:

    使用Select-String,它通过传递给其
    -Pattern参数的字符串数组支持多个搜索条件:

    Select-String -NotMatch -SimpleMatch -Pattern (Get-Content -Path .\badPhrases.txt) .\inputfile.txt |
     Select-Object -ExpandProperty Line | 
       Out-File .\clean_data.txt -Force
    

    字符编码警告:在 Windows PowerShell 中,Out-File 默认创建“Unicode”(UTF-16LE)文件,其中每个字符(至少)由 2字节;在 PowerShell [Core] 6+ 中,默认为更合理的 BOM-less UTF-8;使用-Encoding参数显式控制字符编码。

    • -NotMatch 否定匹配,因此只输出匹配任何模式字符串的行。

    • -SimpleMatch 确保模式与输入文件的行匹配字面意思;默认情况下,它们被解释为正则表达式。

    • 请注意,默认情况下匹配是不区分大小写的;如果需要,请使用-CaseSensitive

    • 由于Select-String默认输出Microsoft.PowerShell.Commands.MatchInfoinstances,所以需要Select-Object -ExpandProperty Line来提取行本身。

      • 注意:在 PowerShell 7+ 中,您可以改用Select-String-Raw 开关。

    至于你尝试了什么

    $_ -notlike $arrayFromFile

    您不能将数组用作字符串比较运算符的 RHS,例如 -like-match-eq - 您只能匹配 one一个字符串。

    (除此之外,-like / -notlike 默认匹配 整个 LHS;要匹配 LHS 的 子字符串,您必须将 * 放在 RHS 的任一端。)

    更多信息请参见this answer

    $arrayFromFile -notin $_

    $_ -notcontains $arrayFromFile

    原则上,您必须反转 containment operators -in and -contains 的操作数及其否定 - 语法是 <array> -contains <value><value> -in <array> - 但问题是,再次匹配的整个字符串以任何一种方式执行,所以这种方法只有在$arrayFromFile包含完整的行出现在输入中时才有效(-in-contains隐式执行每个元素 -eq 比较)。

    【讨论】:

    • 当我这样运行时,我的输出文件最终还是比我的输入文件大!但是:我注意到,但我忽略了这个细节,一些“坏短语”包含特殊字符;例如大于、小于、逗号、斜杠和反斜杠。您认为我需要转义这些特殊字符,还是将它们封装在“badPhrases.txt”文件中的引号中?
    • @Pink:大小增加很可能来自 Windows PowerShell(但不是 PowerShell Core)中创建“Unicode”文件 (UTF-16LE) 中的 Out-File - 请参阅我的更新。不,如果你使用-SimpleMatch,你不需要转义特殊字符。
    • 这太棒了,非常感谢.. 所以它似乎工作了;我正在尝试将对象与使用 grep 并花费 100 年的旧 .bat 文件的输出进行比较。差异需要一些时间。我将输出文件类型更改为 utf8,不是出于兼容性考虑,而是为了让我可以很快看到我的输出是否接近其他方法。 (是的;这个方法是~69MB,另一种是~71Mb)。很快就会标记为已回答!
    • 很高兴听到它有帮助,@Pink。结果是否符合预期?请注意,在 Windows PowerShell 中另存为 UTF-8 总是会添加 3 字节的 UTF-8 BOM。
    • 是的 - 这似乎工作得很好。事实上,它捕获了几千行我们没有得到的基于“grep”的批处理文件!我永远不会想出选择字符串和扩展的东西,所以非常感谢!我们并不像我想象的那样担心文件格式;这些文件不会返回到它们起源的大型机。
    猜你喜欢
    • 1970-01-01
    • 2014-08-11
    • 2013-10-10
    • 1970-01-01
    • 2021-01-08
    • 2018-06-28
    • 2021-08-09
    • 1970-01-01
    相关资源
    最近更新 更多