Оператор switch
с параметром -File
- это самый быстрый способ обработки больших файлов в PowerShell [1] :
& {
switch -File $infile -Regex {
$match_regex {
# Join the what all the capture groups matched, trimmed, with a tab char.
$Matches[1..($Matches.Count-1)].Trim() -join "`t"
}
}
} | Out-File $outFile # or: Set-Content $outFile (beware encoding issues)
С выводом текста,Out-File
и Set-Content
могут использоваться взаимозаменяемо, но не в том, что в Windows PowerShell они по умолчанию используют разные кодировки символов (UTF-16LE и Ansi);используйте -Encoding
по мере необходимости;PowerShell Core постоянно использует UTF-8 без спецификации.
Примечание:
Чтобы пропустить строку заголовка или захватите его отдельно, либо предоставьте для него отдельное регулярное выражение, либо, если заголовок также соответствует регулярному выражению строки данных, инициализируйте переменную индекса строки перед оператором switch
(например, $i = 0
) и проверьте и увеличьте егопеременная в блоке сценария обработки (например, if ($i++ -eq 0) { ... }
).
.Trim()
неявно вызывается для каждой строки в массиве , возвращаемой $Matches[1..($Matches.Count-1)]
;эта функция называется перечисление члена
Причина, по которой оператор switch
заключен в & { ... }
( блок сценария ({ ... }
), вызываемый оператором вызова (&
) ), заключается в том, что составные операторы, такие как switch
/ while
, foreach (...)
, ... не являются напрямую поддерживается в качестве входных данных конвейера - см. этот выпуск GitHub .
Что касается того, что вы пытались :
Как указывает iRon , вы не должны использовать $Input
в качестве пользовательской переменной - это автоматическая переменная , управляемая PowerShellи, фактически, все, что вы назначаете ему, тихо отбрасывается .
Как AdminOfThings указывает:
$element = $_.trim()
не работает, потому что вы находитесь внутри foreach
цикла , а не в конвейере с командлетом ForEach-Object
(хотя последний также связан сforeach
; только с ForEach-Object
будет установлено $_
вurrent входной объект.
Нет необходимости в пользовательской функции только для соединения элементов массива с разделителем;оператор -join
делает это напрямую, как показано выше.
Lee_Daily показывает, как использовать -join
напрямую с массивом $Matches
, как использовалось выше.
Несколько сторон:
Join-Str($matches)
Вместо этого следует использовать Join-Str $matches
:
В PowerShell функции вызываются как команды оболочки - foo arg1 arg2
- не как методы C # - foo(arg1, arg2)
;см. Get-Help about_Parsing
.
Если вы используете ,
для разделения аргументов, вы создадите массив , который функция будет рассматривать как единственный аргумент.
Чтобы предотвратить случайное использование синтаксиса метода, используйте Set-StrictMode -Version 2
или выше, но обратите внимание на его другие эффекты.
| Out-Null
Почти всегда более быстрый метод подавления выходного сигнала заключается в использовании $null = ...
.
[1] Mark (OP) сообщает о значительном ускорении по сравнению с Get-Content
+ ForEach-Object
подход в вопросе (решение switch
занимает 7,7 минут для файла объемом 4 ГБ).
Хотя решение switch
, скорее всего, достаточно быстрое в большинстве сценариев, этот ответ показываетрешение, которое может быть быстрее для большого числа итераций; этот ответ противопоставляет его решению switch
и показывает тесты с переменным числом итераций.
Помимо этого, скомпилированное решение, написанное, скажем, на C #, является единственным способомдля дальнейшего улучшения производительности.