PowerShell正则表达式匹配只匹配一次

时间:2017-04-15 03:05:05

标签: regex powershell

我正在尝试运行使用字母日期命名的文件,并相应地设置文件日期时间。我的代码运行正常,当我注意到这个问题时,我已经准备好考虑它了。我的代码应检测两个日期并生成错误,但事实并非如此。我已经提取了相关代码,并重新创建了问题:

$str = "test20001231 20170415.txt"
$match = ($str -match "(?<=\b|\D)20\d{6,6}(?=\b|\D)")
"$match"
"$($Matches.length)"
"$($Matches[0].ToString())"

给出这个输出:

True
1
20001231

我对正则表达式代码的理解是它应该匹配从20开始的8位数字的所有内容,无论它在字符串中的哪个位置,除非它跟随或在另一个数字之前。所以我期待$ Matches.length为2。

我已经在网上测试了许多地方的正则表达式代码,它符合我期望的两个日期: http://regexstorm.net/tester?p=%28%3f%3c%3d%5cb%7c%5cD%2920%5cd%7b6%2c6%7d%28%3f%3d%5cb%7c%5cD%29&i=test20001231+20170415.txt http://www.phpliveregex.com/p/jLA

此问题适用于PS和PS ISE。我搜索了很多(我认为),并没有提出任何有用的信息。 有什么建议? 提前谢谢了, 戴夫

1 个答案:

答案 0 :(得分:7)

PowerShell的-match运算符只查找每个输入字符串的第一个匹配(如果有),因为它的目的是 test for a (any)匹配,无论是否有多个匹配。

请注意,如果LHS是数组,则单个-match表达式可以包含多个输入字符串,在这种情况下,返回匹配的元素数组;例如:'foo', 'bar', 'baz' -match 'b'产生数组'bar', 'baz'。但是,对于每个数组元素,只会再次测试单个匹配,并且在这种情况下甚至不会填充自动$Matches变量 - 请参阅bottom。 / SUP>

以下所有命令都假定PSv3 +,但也可以在v2中使用。

您需要使用.NET框架的[regex]类来获取多个匹配

PS> ([regex]::Matches('test20001231 20170415.txt', '(?<=\b|\D)20\d{6,6}(?=\b|\D)')).Value
20001231
20170415

[regex]::Matches()输出[System.Text.RegularExpressions.Match]个实例 [1] 的集合,其.Value属性包含匹配项。

注意.Value如何应用于整个集合,在PSv3 +中  自动将集合成员的属性值作为数组返回。

只获得匹配的计数

PS> ([regex]::Matches('test20001231 20170415.txt', '(?<=\b|\D)20\d{6,6}(?=\b|\D)')).Count
2

另一种选择是使用Select-String -AllMatches ,它会输出[Microsoft.PowerShell.Commands.MatchInfo]个实例  其.Matches属性包含每行[System.Text.RegularExpressions.Match]个实例的集合:

PS> ('test20001231 20170415.txt' |
    Select-String -AllMatches '(?<=\b|\D)20\d{6,6}(?=\b|\D)').Matches.Value
20001231
20170415

如上所述,用.Count代替.Value输出匹配数。

请注意,使用 Select-String对于单个输入字符串来说有点笨拙,但是用于大型输入集合的正确工具,例如文件的行。

可选阅读:自动$Matches变量:

填充自动$Matches变量(自PSv5.1起):

    使用-match运算符时,只能
  • LHS是标量
    • 相比之下,LHS上的数组$Matches既未填充也未重置。
  • 找到
  • 匹配项(-match返回$true
    • 如果找到没有匹配(-match返回$false),则预先存在的$Matches值(如果有)保持不变。

$Matches[hashtable]个实例,其中包含以下条目:

  • key 0的条目是整个匹配 - 根据定义,此密钥始终存在。
  • key <n>的条目是 - 未命名 - 与索引<n>匹配的捕获组。
  • <name>的条目是名称捕获组<name>匹配的内容。

$Matches(可能)还包含捕获组值的事实证明了其复数名称 - 尽管只匹配单个出现的正则表达式。< / p>

[1]要检查单个对象的类型或集合元素的类型,请管道Get-Member([regex]::Matches('foo', 'o')) | Get-Member
要检查集合本身的类型,请将其传递给Get-Member -InputObject
Get-Member -InputObject ([regex]::Matches('foo', 'o'))