从字符串中拆分数字和字母会丢失零



我正在处理一个时间值,该时间值以T开头,然后是一系列数字,后面紧跟着每个数字的单位。例如,8小时22分钟将作为T8H22M,3小时2分钟1秒将作为T3H2M1S

我需要将这个编码的值拆分为单独的H/M/S列,但我在获取零以正常工作时遇到了问题。我使用的是另一个问题中的代码,这里有类似(但不完全相同(的要求。

此脚本:

Write-Host $('T8H22M' -split { [bool]($_ -as [double]) })
Write-Host $('T8H22M' -split { ! [bool]($_ -as [double]) })
Write-Host $('T8H0M' -split { [bool]($_ -as [double]) })
Write-Host $('T8H0M' -split { ! [bool]($_ -as [double]) })
Write-Host $('T0H' -split { $_ -eq '0' })

产生此输出:

T H  M
8 22 
T H0M
8   
T H

正如你所看到的,任何时候数值为零,字符串都不会分裂。这是一个真正的问题,因为零时间作为T0H出现,它不会使用上面的方法进行解析。

我如何修改上面的代码以同时拆分零值?

您可以使用正则表达式来提取值。例如:

'T3H2M1S','T8H22M','T8H0M','T0H' |
ForEach-Object {
if($_ -match '^T((?<hours>d+)H)*((?<minutes>d+)M)*((?<seconds>d+)S)*$') {
[PsCustomObject]@{
TimeString = $matches.0
Hours      = [Int]$matches.hours
Minutes    = [Int]$matches.minutes
Seconds    = [Int]$matches.seconds
}
}
}

这为每个时间字符串生成一个对象,其中HoursMinutesSeconds属性对应于该字符串的相关部分:

TimeString Hours Minutes Seconds
---------- ----- ------- -------
T3H2M1S        3       2       1
T8H22M         8      22       0
T8H0M          8       0       0
T0H            0       0       0

当然,您可以随意更改if的内容来操作值,而不仅仅是创建一个对象——关键是RegEx应该为您正确地拆分它。

*-我说"应该",因为我只测试了你给出的示例字符串,所以一定要自己测试得更彻底

您拥有的时间值类似于ISO 8601持续时间格式,只是它们都缺少前导P

您可以使用.netSystem.Xml.XmlConvertToTimeSpan()方法,使用将这些转换为时间跨度

'T3H2M1S','T8H22M','T8H0M','T0H' | ForEach-Object { 
[System.Xml.XmlConvert]::ToTimeSpan("P$_")  # prepend a 'P'
}

返回TimeSpan对象数组

Days              : 0
Hours             : 8
Minutes           : 22
Seconds           : 0
Milliseconds      : 0
Ticks             : 301200000000
TotalDays         : 0,348611111111111
TotalHours        : 8,36666666666667
TotalMinutes      : 502
TotalSeconds      : 30120
TotalMilliseconds : 30120000
Days              : 0
Hours             : 8
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 288000000000
TotalDays         : 0,333333333333333
TotalHours        : 8
TotalMinutes      : 480
TotalSeconds      : 28800
TotalMilliseconds : 28800000
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 0
TotalDays         : 0
TotalHours        : 0
TotalMinutes      : 0
TotalSeconds      : 0
TotalMilliseconds : 0

现在,您可以使用任何属性进行格式化。

为了赞扬@boxdog和@Theo对实际问题的回答为什么缺少零和"我如何修改上面的代码以同时拆分零值">

引用<ScriptBlock>参数

<ScriptBlock>
指定应用分隔符规则的表达式。这个表达式必须计算为$true$false。封装脚本块在大括号中。

这里的要点是0评估为$False("falsy"(:

if (0) { 'True' } else { 'False' }
False
if (1) { 'True' } else { 'False' }
True
[Bool]0
False
[Bool]1
True

换句话说,你需要将你的分裂表达式与$Null进行比较,以获得你想要的:

Write-Host $('T8H22M' -split { $Null -ne ($_ -as [double]) })
T H  M
Write-Host $('T8H22M' -split { $Null -eq ($_ -as [double]) })
8 22
Write-Host $('T8H0M' -split { $Null -ne ($_ -as [double]) })
T H M
Write-Host $('T8H0M' -split { $Null -eq ($_ -as [double]) })
8 0

无论如何,我建议你选择@boxdog或@Theo的解决方案。

最新更新