拆分和正则表达式与 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
    )
}

详情见https://regex101.com/r/8oSpqf/1

的更简洁 - 尽管可能更晦涩 - 替代:

# 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] 个实例)。