使用PowerShell和正则表达式,我试图解释数据文件中的时间字符串,例如字符串12h30m
表示12小时30分钟,或15m
表示15分钟,1m30s
,2h
等。我想我可以使用正则表达式拆分这些字符串以分隔小时分钟和秒,并且只得到数字部分,所以省略h
,m
,s
,然后做一些计算。
然而,我设法让一个正则表达式工作,但只有当我还包括h
,m
,s
时,我的意思是当我在正则表达式中添加“积极前瞻”部分时,最终结果不是我所期望的。
下面是PowerShell脚本
$input = "12h34m56s"
#$input = "4h30m"
#$input = "1m15s"
#$input = "14400"
Write-Output "--(test 1)--------------------"
$input -match '(\d*h)?(\d*m)?(\d*s)?(\d*)?'
Write-Output $Matches
Write-Output "--(test 2)--------------------"
$input -match '(\d*(?=h))?(\d*(?=m))?(\d*(?=s))?(\d*)?'
Write-Output $Matches
输出如下:
--(test 1)--------------------
True
Name Value
---- -----
4
3 56s
2 34m
1 12h
0 12h34m56s
--(test 2)--------------------
True
4
1 12
0 12
第一部分“test1”是我所期望的,但是对于第二部分“test2”,我期望的是这样的输出
--(test 2)--------------------
True
Name Value
---- -----
4
3 56
2 34
1 12
0 12h34m56s
我测试了这个on regex101,看语法颜色似乎是正确的,但在顶部它说“27匹配”,我希望只有5个匹配(因为5行)。所以我怀疑它与分组有关。我试图在整个周围添加额外的括号,但没有帮助。任何帮助都将不胜感激。
3条答案
按热度按时间u5rb5r591#
如果你想用正则表达式来做这件事,你可能会期待一个正则表达式的答案,但未来的读者应该意识到这应该使用
TimeSpan.ParseExact
来完成。注意,调用此重载时需要强制转换
[string[]]
。7xllpg7q2#
正如mclayton评论的那样,您可以在许多格式上使用
[timespan]::ParseExact()
方法。在你的例子中,唯一的问题是当字符串只包含数字时,在这种情况下,使用
[timespan]::new()
构造函数并将字符串的数值乘以10000000以将秒转换为Ticks:bvpmtnay3#
使用**
[timespan]::ParseExact()
,如其他有用的答案所示,如果/一旦您有表示时间跨度的单独令牌,则绝对是首选。然而,至少假设你可能(首先)必须从一个更大的文本*中提取这样的标记 *,在这种情况下,需要正则表达式 *-见下文。
你的正则表达式的问题**是使用lookaheadAssert(例如,
(?=h)
)会阻止你的正则表达式将12h34m56s
等标记识别为 * 单一 * 匹配,因为lookaroundAssert不会 * 消耗 * 它们匹配的子字符串。因此,只需直接匹配这些字符,并将子表达式包含在
(?:…)
中,即 * 非捕获 * 组,以避免不必要的捕获组;例如,使用(?:(\d+)h)?
代替(\d*h)?
。还要注意使用
+
而不是+
,因为至少应该存在 * 一个 * 数字,而子表达式 * 作为整体 * 可能不存在((?:…)?
)将所有这些放在一起,沿着使用 named 捕获组,这使得更容易识别哪个捕获组匹配捕获了哪些单元:
输出: