Private/Split-NSPFortiGateLineBatch.ps1

function Split-NSPFortiGateLineBatch {
    <#
    .SYNOPSIS
        Tokenizes every line at once, for the tree builder: one string[] per line, or $null for a line
        that leaves a quote open.
    .DESCRIPTION
        Same rules as Split-NSPFortiGateToken, which handles the open-quote lines (and the multi-line
        text they start). Kept apart from Read-NSPFortiGateConfigTree on purpose, for speed:
          - one call for the whole file, since calling a function per line costs more than the split
            itself on Windows PowerShell 5.1 (about 0.3 ms a call);
          - its own small loop, which PowerShell 7 runs several times faster than the same code inside
            the tree builder's larger loop.
        Together that took a 20,000-line backup from 12 seconds to under 2.
    #>

    [OutputType([object[]])]
    param([Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]]$Text)

    $linePattern = $script:NSPFortiGateLinePattern
    $quotedPattern = $script:NSPFortiGateQuotedPattern
    $unquote = $script:NSPFortiGateUnquote
    $result = [object[]]::new($Text.Count)
    for ($n = 0; $n -lt $Text.Count; $n++) {
        $line = $Text[$n]
        if ($line.IndexOf([char]34) -lt 0) {
            $result[$n] = [string[]]$line.Split([char[]]$null, [StringSplitOptions]::RemoveEmptyEntries)
            continue
        }
        $match = $linePattern.Match($line)
        if (-not $match.Success) { continue }
        $captures = $match.Groups['token'].Captures
        $tokens = [string[]]::new($captures.Count)
        for ($c = 0; $c -lt $captures.Count; $c++) {
            $token = $captures[$c].Value
            if ($token.IndexOf([char]34) -ge 0) {
                # Most quoted tokens are one plain "..." run; the regex evaluator is only for escapes.
                if ($token.IndexOf([char]92) -ge 0) { $token = $quotedPattern.Replace($token, $unquote) }
                elseif ($token.Length -ge 2 -and $token[0] -eq [char]34 -and $token.IndexOf([char]34, 1) -eq $token.Length - 1) { $token = $token.Substring(1, $token.Length - 2) }
                else { $token = $quotedPattern.Replace($token, '$1') }
            }
            $tokens[$c] = $token
        }
        $result[$n] = $tokens
    }
    , $result
}