为什么我的Powershell是regex '?' quantifier未按预期为整个捕获组工作

nhhxz33t  于 2023-08-08  发布在  Shell
关注(0)|答案(1)|浏览(114)

我有一个Powershell正则表达式,当我添加'?'限定符添加到整个捕获组。
带'的正则表达式?' quantifier没有返回预期的结果。在这种情况下,我期望的结果与没有量词的结果相同。

$rec = " latest handshake: 128 days, 2 hours, 50 minutes, 33 seconds ago"
$rec -match "((?<Days>\d+)\sdays?(,\s+))?";
True
Matches;

Name                           Value
----                           -----
0

字符串
没有最后一个?'显示捕获组按预期进行了分析。

$rec = " latest handshake: 128 days, 2 hours, 50 minutes, 33 seconds ago"
$rec -match "((?<Days>\d+)\sdays?(,\s+))";
True
$Matches;

Name                           Value
----                           -----
Days                           132
2                              ,
1                              132 days,
0                              132 days,


下面的代码段显示在结尾使用量词是有效的。

"abc" -match "((abc)d?)?"
True
$Matches

Name                           Value
----                           -----
2                              abc
1                              abc
0                              abc


首先,我是新来的,所以如果有比修改问题更好的方法来回应评论,请告诉我。
对不起,我遗漏了$rec字符串赋值。源来自WireGuard服务器报告。我的脚本的目标是在几分钟内计算最后一次握手。我打算创建一个可选的捕获组几天?小时?分钟?,秒?然后基于当前捕获来计算分钟。
可能的$rec字符串:

  • 最新握手:128天2小时50分钟33秒前
  • 最新握手:1 day,2 hours,50 minutes,33 seconds ago
  • 最新握手:4小时21分钟48秒前
  • 最新握手:1小时45秒前
  • 最新握手:1 hour,1 minute,22 seconds ago
  • 最新握手:2分钟,1秒前
  • 最新握手:2分钟前
  • 最新握手:2秒前
  • 最新握手:1秒前
  • 最新握手:现在开始

最后一个代码片段(下面使用命名的捕获组重复)显示为捕获组添加量词返回的结果与不添加量词时相同。我一定是做错了什么,附加的量词不能和原始的$rec一起工作。

#Without last quantifier #Without last quantifier
"abc" -match "(?<cap>()(abc)d?)"
True
Stats> $Matches

Name                           Value
----                           -----
cap                            abc
2                              abc
1
0                              abc

#With last quantifier
"abc" -match "(?<cap>(abc)d?)?"
True
Stats> $Matches

Name                           Value
----                           -----
cap                            abc
1                              abc
0                              abc

2ic8powd

2ic8powd1#

这个问题是众所周知的:如果你所有的模式都匹配一个空字符串,并且你在一个正则表达式方法中只搜索一次匹配,而预期的匹配碰巧位于字符串中间的某个地方,正则表达式引擎会在输入字符串的开头“找到”空字符串,并将其作为有效匹配返回。
您似乎想用一个正则表达式解析时间段,该正则表达式用于一个search-once -match正则表达式方法。
你可以使用一个正则表达式来查找字符串中任何已知单词之前的数字:

> $rx = '^(?=.*?(?<Days>\d+)\s*days?\b)?(?=.*?(?<Hours>\d+)\s*h(?:ou)?rs?\b)?(?=.*?(?<Minutes>\d+)\s*min(?:utes?)?\b)?(?=.*?(?<Seconds>\d+)\s*sec(?:ond)?s?\b)?(?=.*?(?<Now>\bNow\b))?'
> $rec = " latest handshake: 128 days, 2 hours, 50 minutes, 33 seconds ago"
> $rec -match $rx | Out-Null
> $Matches

Name                           Value
----                           -----
Hours                          2
Days                           128
Minutes                        50
Seconds                        33
0

字符串
然后,您可以根据需要处理组编号。

注意:* 这个正则表达式只适用于已知只包含一个有效时间段 * 的字符串。

参见regex demo

  • 详细信息 *:
  • ^-字符串的开头
  • (?=.*?(?<Days>\d+)\s*days?\b)?-一个可选的正向前查找,如果后面紧跟着零个或多个字符,而不是尽可能少的换行符,然后是一个或多个数字(捕获到名为捕获组的Days中),然后是零个或多个空格,然后是day,一个可选的s后面跟着一个单词边界,则将匹配当前位置。
  • (?=.*?(?<Hours>\d+)\s*h(?:ou)?rs?\b)?-一个可选的正向前查找,如果后面紧跟着零个或多个字符,而不是尽可能少的换行符,然后是一个或多个数字(捕获到名为Hours的捕获组中),然后是零个或多个空格,然后是hourhr,然后是一个可选的s,后面跟着一个单词边界,则将匹配当前位置
  • (?=.*?(?<Minutes>\d+)\s*min(?:utes?)?\b)?-一个可选的积极的前瞻,如果紧随其后的是任何零个或多个字符,而不是尽可能少的换行符字符,然后是一个或多个数字,则将匹配当前位置。(捕获到名为捕获组的Minutes中),然后是零个或多个空格,然后是minminute,然后是可选的s,后跟字边界
  • (?=.*?(?<Seconds>\d+)\s*sec(?:ond)?s?\b)?-一个可选的积极的前瞻,如果紧随其后的是任何零个或多个字符,而不是尽可能少的换行符字符,然后是一个或多个数字,则将匹配当前位置。(捕获到名为捕获组的Seconds中),然后是零个或多个空格,然后是secsecond,然后是可选的s,后跟字边界
  • (?=.*?(?<Now>\bNow\b))?-一个可选的积极前瞻,将匹配当前位置,如果它后面紧跟着任何零个或多个字符,而不是尽可能少的换行符,然后是一个Now字符串(捕获到Now命名的捕获组),后面跟着一个单词边界。

相关问题