如何根据起始行将文本块拆分为多行记录?

How can I split a block of text into multiline records based on the starting line?

提问人:xeric080 提问时间:10/25/2023 更新时间:10/25/2023 访问量:48

问:

我怎样才能把它拆分成单独的字符串/数组/等,以便我可以分别迭代每个字符串/数组/等?目标是将它们分开,以便我可以分析每条记录并插入到 PSCustomObject 中。

我有以下表示 1 次以上扫描的文本块。每条扫描记录都以“根扫描路径”行开头,以“可疑文件”行结尾。

我能够得到的最接近的是以下行,它有效,但后来我丢失了“根扫描路径”行,因为它是分隔符。

$String -Split "Root Scan Path: C:\\"

也可能有 2 个以上的扫描记录。

Root Scan Path: C:\
Scan ID: 03307ad8-1a59-7d4e-8dfe-28864c9d1bc2
Status: Completed
Initiated from: User
Start Time: Monday, October 23, 2023 9:24:18 PM
End Time: Monday, October 23, 2023 9:34:00 PM
Scanned Files: 38311
Unsupported Files: 229479
Traversed Files: 321202
Total Files: 267790
Suspicious Files: 0
Root Scan Path: C:\
Scan ID: f32a64b0-56f5-664c-bf37-a7b120f759d8
Status: Running
Initiated from: User
Start Time: Tuesday, October 24, 2023 6:20:45 PM
End Time:
Scanned Files: 0
Unsupported Files: 0
Traversed Files: 0
Total Files: 0
Suspicious Files: 0
数组字符串 PowerShell 拆分

评论


答:

2赞 Olaf 10/25/2023 #1

我会拆分换行符,并用唯一字符(例如等号)替换冒号的第一个出现,并用于获取正确的 PowerShell 对象。ConvertFrom-StringData

@'
Root Scan Path: C:\
Scan ID: 03307ad8-1a59-7d4e-8dfe-28864c9d1bc2
Status: Completed
Initiated from: User
Start Time: Monday, October 23, 2023 9:24:18 PM
End Time: Monday, October 23, 2023 9:34:00 PM
Scanned Files: 38311
Unsupported Files: 229479
Traversed Files: 321202
Total Files: 267790
Suspicious Files: 0
Root Scan Path: C:\
Scan ID: f32a64b0-56f5-664c-bf37-a7b120f759d8
Status: Running
Initiated from: User
Start Time: Tuesday, October 24, 2023 6:20:45 PM
End Time:
Scanned Files: 0
Unsupported Files: 0
Traversed Files: 0
Total Files: 0
Suspicious Files: 0
'@ -split "\r?\n" |
    ForEach-Object {
        $_ -replace ':(?=\s|$)',' ='
    } | ConvertFrom-StringData -Delimiter '='

输出如下所示:

Name                           Value
----                           -----
Root Scan Path                 C:
Scan ID                        03307ad8-1a59-7d4e-8dfe-28864c9d1bc2
Status                         Completed
Initiated from                 User
Start Time                     Monday, October 23, 2023 9:24:18 PM
End Time                       Monday, October 23, 2023 9:34:00 PM
Scanned Files                  38311
Unsupported Files              229479
Traversed Files                321202
Total Files                    267790
Suspicious Files               0
Root Scan Path                 C:
Scan ID                        f32a64b0-56f5-664c-bf37-a7b120f759d8
Status                         Running
Initiated from                 User
Start Time                     Tuesday, October 24, 2023 6:20:45 PM
End Time
Scanned Files                  0
Unsupported Files              0
Traversed Files                0
Total Files                    0
Suspicious Files               0
3赞 Santiago Squarzon 10/25/2023 #2

假设每个块之间没有空行,则以下方法可能有效:

$out = [ordered]@{}
$theInputString -split '\r?\n(?=Root Scan Path:)' | ForEach-Object {
    foreach ($line in $_ -split '\r?\n') {
        $key, $value = $line.Split(':', 2).Trim()
        $out[$key] = $value
    }
    [pscustomobject] $out
    $out.Clear()
}

为了简单起见,我建议 Olaf 使用 ConvertFrom-StringData,但是该 cmdlet 有一个警告,即它不保留属性的顺序(因为哈希表不确保其键顺序), 我注意到的另一个警告是它使用字符串中的反斜杠 \(不确定是否记录了):

'Root Scan Path=C:\' | ConvertFrom-StringData


为了澄清上述情况,正如 mklement0 在注释中指出的那样,正在使用的反斜杠是预期的,该字符需要用另一个反斜杠进行转义。另请参阅 GitHub 问题 #20418

'Root Scan Path=C:\\' | ConvertFrom-StringData

Name                           Value
----                           -----
Root Scan Path                 C:\

评论

2赞 Olaf 10/25/2023
非常整洁。👍🏼 我实际上错过了实际上有 2 个数据集。🤭🤷🏼‍♂️
2赞 Santiago Squarzon 10/25/2023
谢谢@Olaf,您的方法也很好用,只需要稍作更改,请参阅此处: i.imgur.com/Vk2zu0n.png // 我不确定这个 cmdlet 消耗 tho 是怎么回事,这很糟糕\
1赞 xeric080 10/25/2023
我从你的两个答案中学到了一些有用的东西,所以谢谢!我将接受这个问题,因为问题的核心是关于将文本块拆分为两组单独的数据集。您的解决方案在第一次拆分中包含它。👍
2赞 Olaf 10/25/2023
@SantiagoSquarzon 当你提到它时,我注意到缺少反斜杠。🤷🏼 ♂️ 这不会打扰我,但你是对的——这很奇怪。无论如何,我认为您的方法更加复杂和强大。👍🏼
2赞 mklement0 10/25/2023
来自 ConvertFrom-StringData:“cmdlet 可以使用方法将反斜杠 () 解释为字符串数据中的转义字符”。另请参阅:GitHub 问题 #20418,建议通过开关选择退出。\Regex.Unescape-Raw