代码之家  ›  专栏  ›  技术社区  ›  Jeremiah Williams

从选择字符串中提取每行的最后一个字

  •  2
  • Jeremiah Williams  · 技术社区  · 7 年前

    从文件中提取文本时遇到问题。我最终想做的是:

    1. 在特定文件中搜索短语“norequest”的实例。
    2. 只取norequest的值。也就是说,如果norequest=true,那么它只会向数组添加“true”,而不是整行。
    3. 对文件中短语的每个实例执行此操作。

    下面是我正在处理的部分的一个片段:

    $FileContents = Select-String -Path "C:\Users\me\Documents\file.ini" -Pattern "NoRequest"
    

    当我使用该行时,我得到以下信息:

    PS> $FileContents
    Documents\file.ini:222:NoRequest = false
    Documents\file.ini:281:NoRequest = false
    Documents\file.ini:347:NoRequest = false
    Documents\file.ini:387:NoRequest = false
    Documents\file.ini:1035:NOREQUEST = true
    Documents\file.ini:1047:NoRequest = true
    Documents\file.ini:1160:NOREQUEST = true
    Documents\file.ini:1242:NOREQUEST = true
    

    这就是我想要的:

    PS> $FileContents
    false
    false
    false
    false
    true
    true
    true
    true
    

    我试着用管道把代码输入 Select-Object -Last 1 解决方案,但由于我的变量是一个数组,所以它选择数组中的最后一行,而不是每行的最后一个字。我还考虑过取数组,然后做一个“数组中的foreach行,除最后一个词外,切掉所有东西”。我想这是可行的,但这似乎是一个笨拙的解决方案。我相信有一个简单有效的解决办法,但我只是没有看到。

    4 回复  |  直到 7 年前
        1
  •  4
  •   Mathias R. Jessen    7 年前

    你可以使用 -split 在字符串上获取最后一个结果:

    Select-String -Path "C:\Users\me\Documents\file.ini" -Pattern "NoRequest" |ForEach-Object {
        -split $_.Line |Select-Object -Last 1
    }
    
        2
  •  3
  •   TheMadTechnician    7 年前

    或者,您可以直接读取该文件,并将其传递给 Where 语句查找所需行,并使用 $Matches 自动变量。

    $FileContents = Get-Content "C:\Users\me\Documents\file.ini" | 
        Where{$_ -Match 'NoRequest = (true|false)'} | 
        ForEach-Object { $Matches[1] }
    
        3
  •  1
  •   mklement0    7 年前

    小文件,如 *.ini 文件,使用 表达 而不是管道是一个选项,它支持既简洁又具有性能的解决方案(psv4+语法):

    (@(Get-content C:\Users\me\Documents\file.ini) -match 'NoRequest').ForEach({ (-split $_)[-1] })
    
    • @(Get-content C:\Users\me\Documents\file.ini) 以数组形式返回指定文件的行( @(...) 确保返回数组,即使 文件中的行)。

    • -match 用一个 数组 作为左舵驾驶,作为 滤波器 并且只返回那些与指定regex匹配的元素。

    • PSV4+ .ForEach() 方法 然后作用于结果数组的元素,用空格将每个元素拆分为标记( -split )并返回 最后的 令牌( -1 )

    作为旁白: 一元的 形式 -split operator ( -split '...' )表现得像尊者 awk Unix utility 默认情况下是这样的:标记是基于任何非空运行的空格作为分隔符提取的,前面和后面的空格将被忽略。

        4
  •  0
  •   Ansgar Wiechers    7 年前

    将正则表达式更改为 (?<=NoRequest.* )(\w+)$ ,以便它与一行中的最后一个词匹配( \w+ 是一个或多个单词字符, $ 是行尾)只有在它前面有字符串“norequest”时。 (?<=...) 是一个正的lookback断言,它检查模式是否存在,而不使其成为返回匹配的一部分。然后展开匹配的值。

    $file = 'C:\Users\me\Documents\file.ini'
    Select-String -Path $file -Pattern '(?<=NoRequest.* )(\w+)$' | ForEach-Object {
        $_.Matches.Value
    }
    

    如果最后一个词只能是“真”或“假”,则可以通过替换使表达式更具体 \W+ 交替使用:

    Select-String -Path $file -Pattern '(?<=NoRequest.* )(true|false)$' | ForEach-Object {
        $_.Matches.Value
    }