对字符串应用正则表达式过滤器,该字符串在Powershell中出现给定字符后返回值

时间:2018-12-19 12:19:46

标签: powershell

我想构建一个PowerShell脚本,该脚本在字符串中第一次出现给定字符后返回该短语。例如,我想在v字符首次出现后得到所有短语:

blah_v1.2
foo_v1
vbarv_2.4
bar

结果将是

1.2
1
barv_2.4

我试图构建类似这样的东西,但是$ FooVersion返回一个布尔值而不是一个字符串。

$Foo = "blah_v1.1"
$FooVersion = $Foo -match "_v (.*)"

Write-Host $Foo
Write-Host $FooVersion

有什么想法吗?干杯

3 个答案:

答案 0 :(得分:3)

尝试一些可能性:


    <rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration">
        <exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint"/>
        <exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.enableEachParameterAndReturnInspection"/>
        <exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.normalizedTraversableTypeHints"/>
        <exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.normalizedUsefulAnnotations"/>
    </rule>

$Foo = "blah_v1.1"

# using -replace
# returns a string without 'v' as-is
$FooVersion = $Foo -replace '(?:[^v]*v)(.*)', '$1'

# using -split at the first 'v' character
# returns a string without 'v' as-is; use [1] to return '' instead
$FooVersion = ($Foo -split 'v', 2)[-1]

答案 1 :(得分:1)

确保先查找不是v的所有内容,然后是第一个v,然后从$Matches变量中获取捕获的值:

$strings = -split @'
blah_v1.2
foo_v1
vbarv_2.4
bar
'@

$strings |ForEach-Object {
    if($_ -match '[^v]*v(.*)'){
        $Matches[1]
    }
}

答案 2 :(得分:1)

-replace operator与输入字符串数组结合使用可提供一种简洁的解决方案:

# Sample input lines (string array)
$lines = @'
blah_v1.2
foo_v1
vbarv_2.4
bar
'@ -split '\r?\n'

# Perform a regex-based string replacement on each input line,
# so as to only extract the substrings of interest.
$lines -replace '.*?v(.*)', '$1'

以上结果:

1.2
1
barv_2.4
bar

给定一个 array 作为LHS,-replace一一对应于数组的元素。

正则表达式.*?v(.*)非贪婪地(?)匹配任何内容(.*)直到 first v,然后(贪婪地)捕获捕获组(v(...)之后的任何内容,替换操作数中的$1都指向该捕获组,并且由于正则表达式与整个输入字符串匹配,所以输出就是在输入的第一个v之后。

请注意, -replace会按原样传递与正则表达式不匹配的输入,这就是为什么bar不包含{{1}的原因},也出现在输出中;如果您想 省略行而没有v ,如示例输出中所示:

v

请注意@($lines) -match 'v' -replace '.*?v(.*)', '$1' 周围的@(...),这可以确保LHS始终被视为 array ,因为$lines仅充当具有数组的过滤器,值LHS,而不是单个输入字符串(请参见下文)。
(根据定义,以上示例输入是一个数组,但是例如,如果您使用-match从文件中加载行,则单行输入文件将产生单字符串,不在1元素数组中。)

因此,

Get-Content返回包含字母-match 'v'的{​​{1}}元素的子数组,$line然后对其进行运算。

注意:

  • 数组+ v方法对于已经在内存中的集合非常方便快捷。

  • 也就是说,如果您知道输入集可以放入整个内存中,则可以通过捕获表达式(-replace中的管道(cmdlet)输出,或者通过保证数组来提高性能。 ,-replace),(...)可以再次应用于:
    @(...)


关于您尝试过的事情

使用标量 LHS,-replace返回一个布尔值(指示输入是否匹配),如您所见。

但是,使用标量 LHS(仅用于!),PowerShell会在自动@(Get-Content input.txt) -replace '.*?v(.*)', '$1'哈希表中填充有关匹配的匹配项((sub)字符串(条目{{1} }),捕获组值(第一个捕获组的条目-match,...),因此您可以使用此后的 ,如Mathias' answer所示。 / p>