拆分和正则表达式与 Powershell 匹配
Split and regex match with Powershell
假设我有一个文件名字符串,类似于:
test_ABC_19000101_010101.987.txt
,
其中“测试”可以是白色 space、字符、数字等的任意组合。我希望使用 Powershell 提取 19000101_010101
部分(日期和时间)。目前我正在将 -split "_ABC_"
分配给一个变量并获取数组的第二个元素。然后我在随后的时间拆分这个字符串。有没有办法一次性完成这个?
PS
"_ABC_"
是常量,在文件名的所有实例中都保持不变。
如果文件名中永远不会出现多个序列作为时间戳(8 位、_、6 位,那么您可以匹配该数字模式。
PS C:\> 'test_ABC_19000101_010101.987.txt' -match '^.*ABC_(\d{8}_\d{6})\..*'
True
PS C:\> $Matches
Name Value
---- -----
1 19000101_010101
0 test_ABC_19000101_010101.987.txt
PS C:\> $Matches[1]
19000101_010101
您将使用文件名而不是显式字符串。
如果你想从中获得 [System.DateTime]:
PS C:\> [datetime]::ParseExact($Matches[1], 'yyyyMMdd_HHmmss', $null)
Monday, January 1, 1900 01:01:01
这个正则表达式似乎有点矫枉过正,但我认为它应该可以工作,只要 _ABC_
是常量并且有一个 _
将日期与时间分开,还有一个 .
将时间与毫秒分开:
$re = [regex]'(?<=_ABC_)(?<date>\d*)_(?<time>\d*)\.(?<millisec>\d*)(?=\.)'
@'
test_ABC_19000101_010101.987.txt
t' az@ 0est_ABC_20000101_090101.123.txt
tes8as712t_ABC_21000101_080101.456.txt
te098d $st_ABC_22000101_070101.789.txt
[test]_ABC_23000101_060101.101.txt
t?\est_ABC_24000101_050101.112.txt
'@ -split '\r?\n' | ForEach-Object {
$groups = $re.Match($_).Groups
$date = $groups['date']
$time = $groups['time']
$msec = $groups['millisec']
[datetime]::ParseExact(
"$date $time $msec",
"yyyyMMdd HHmmss fff",
[cultureinfo]::InvariantCulture
)
}
的更简洁 - 尽管可能更晦涩 - 替代:
# Construct a regex that consumes the entire file name while
# using capture groups for the parts of interest.
$re = '.+_ABC_(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})\.(\d{3})\..+'
[datetime] (
# In the replacement string, use , , ... to refer to what the
# first, second, ... capture group captured.
'test_ABC_19000101_010101.987.txt' -replace $re, '--T::.'
)
输出:
Monday, January 1, 1900 1:01:01 AM
-replace
操作产生字符串 '1900-01-01T01:01:01.987'
,这是一种(文化不变的)格式,您可以按原样与 [datetime]
转换一起使用。
请注意,使用 Get-ChildItem
调用作为输入,您可以通过提供 $_.BaseName
而不是 $_.Name
作为 -replace
LHS 来稍微简化正则表达式,这样就避免了需要也匹配正则表达式中的 extension (.\.+
)。
旁白 [datetime]
cast: [datetime] '...'
导致 [datetime]
实例是 未指定 时间戳(其 .Kind
属性 值为 Unspecified
),即未定义表示为 Local
还是 Utc
时间戳。
要获得 Local
时间戳,请使用
[datetime]::Parse('...', [cultureinfo]::InvariantCulture, 'AssumeLocal')
(使用 'AssumeLocal, AdjustToUniversal'
获得 Utc
时间戳)。
或者,您可以转换为 [datetimeoffset]
- 一种通常优于 [datetime]
的类型 - 将转换为它的字符串解释为 [=默认为 56=]local。 (然后您可以访问其 .LocalDateTime
/ .UtcDateTime
属性以获取 Local
/ Utc
[datetime]
个实例)。
假设我有一个文件名字符串,类似于:
test_ABC_19000101_010101.987.txt
,
其中“测试”可以是白色 space、字符、数字等的任意组合。我希望使用 Powershell 提取 19000101_010101
部分(日期和时间)。目前我正在将 -split "_ABC_"
分配给一个变量并获取数组的第二个元素。然后我在随后的时间拆分这个字符串。有没有办法一次性完成这个?
PS
"_ABC_"
是常量,在文件名的所有实例中都保持不变。
如果文件名中永远不会出现多个序列作为时间戳(8 位、_、6 位,那么您可以匹配该数字模式。
PS C:\> 'test_ABC_19000101_010101.987.txt' -match '^.*ABC_(\d{8}_\d{6})\..*'
True
PS C:\> $Matches
Name Value
---- -----
1 19000101_010101
0 test_ABC_19000101_010101.987.txt
PS C:\> $Matches[1]
19000101_010101
您将使用文件名而不是显式字符串。
如果你想从中获得 [System.DateTime]:
PS C:\> [datetime]::ParseExact($Matches[1], 'yyyyMMdd_HHmmss', $null)
Monday, January 1, 1900 01:01:01
这个正则表达式似乎有点矫枉过正,但我认为它应该可以工作,只要 _ABC_
是常量并且有一个 _
将日期与时间分开,还有一个 .
将时间与毫秒分开:
$re = [regex]'(?<=_ABC_)(?<date>\d*)_(?<time>\d*)\.(?<millisec>\d*)(?=\.)'
@'
test_ABC_19000101_010101.987.txt
t' az@ 0est_ABC_20000101_090101.123.txt
tes8as712t_ABC_21000101_080101.456.txt
te098d $st_ABC_22000101_070101.789.txt
[test]_ABC_23000101_060101.101.txt
t?\est_ABC_24000101_050101.112.txt
'@ -split '\r?\n' | ForEach-Object {
$groups = $re.Match($_).Groups
$date = $groups['date']
$time = $groups['time']
$msec = $groups['millisec']
[datetime]::ParseExact(
"$date $time $msec",
"yyyyMMdd HHmmss fff",
[cultureinfo]::InvariantCulture
)
}
# Construct a regex that consumes the entire file name while
# using capture groups for the parts of interest.
$re = '.+_ABC_(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})\.(\d{3})\..+'
[datetime] (
# In the replacement string, use , , ... to refer to what the
# first, second, ... capture group captured.
'test_ABC_19000101_010101.987.txt' -replace $re, '--T::.'
)
输出:
Monday, January 1, 1900 1:01:01 AM
-replace
操作产生字符串 '1900-01-01T01:01:01.987'
,这是一种(文化不变的)格式,您可以按原样与 [datetime]
转换一起使用。
请注意,使用 Get-ChildItem
调用作为输入,您可以通过提供 $_.BaseName
而不是 $_.Name
作为 -replace
LHS 来稍微简化正则表达式,这样就避免了需要也匹配正则表达式中的 extension (.\.+
)。
旁白 [datetime]
cast: [datetime] '...'
导致 [datetime]
实例是 未指定 时间戳(其 .Kind
属性 值为 Unspecified
),即未定义表示为 Local
还是 Utc
时间戳。
要获得 Local
时间戳,请使用
[datetime]::Parse('...', [cultureinfo]::InvariantCulture, 'AssumeLocal')
(使用 'AssumeLocal, AdjustToUniversal'
获得 Utc
时间戳)。
或者,您可以转换为 [datetimeoffset]
- 一种通常优于 [datetime]
的类型 - 将转换为它的字符串解释为 [=默认为 56=]local。 (然后您可以访问其 .LocalDateTime
/ .UtcDateTime
属性以获取 Local
/ Utc
[datetime]
个实例)。