Powershell улучшил производительность и эффективность кодирования при очистке текста и выводе в файл

Первый раз пишу PS скрипт. Предполагается, что источником являются данные, разделенные вертикальной чертой, которые соответствуют некоторым ограничениям. Этот скрипт предназначен для выявления записей в источнике, которые нарушают некоторые правила. Я в основном использовал документацию Microsoft, чтобы узнать достаточно, чтобы добраться до этого момента.

Вопросы:

  1. Существуют ли альтернативы ReadLines, out-file или тому, как я структурировал цикл foreach, который будет лучше работать с очень большими файлами (~ десятки ГБ)?
  2. Можно ли хранить код в массиве/функции/? чтобы получить к нему доступ позже и выполнить его с аргументом. Например, вместо того, чтобы писать логику для регулярного выражения или сравнения длины строки для каждой строки, возможно, функция для длины строки, которая принимает строку и длину, выполняет оценку и проходит или не проходит?
  3. Как определить минимальную версию для различных командлетов, которые я использую?
  4. Существуют ли существующие командлеты, которые обрабатывают тот тип проверки, который я пытаюсь выполнить изначально?

Спасибо

$record=''
$ary=''
$Nrecord=0
foreach ($record in [System.IO.File]::ReadLines("..."))
{
$results=''
$Nrecord++
$ary=$record.split('|')
if (($ary[0])    -and ($ary[0].length -gt 50))       {$results=$results + "$Nrecord|1|A|String length`r"} 
if (($ary[1])    -and ($ary[1].length -gt 50))       {$results=$results + "$Nrecord|2|A|String length`r"}
if (($ary[2])    -and ($ary[2] -notmatch "^[012]{1}$"))  {$results=$results + "$Nrecord|3|B|Category`r"}
if (($ary[4])    -and ($ary[4] -notmatch "^[0-9]{2}$"))  {$results=$results + "$Nrecord|5|B|Category`r"}
if (($ary[5])    -and ($ary[5] -notmatch "^[123]{1}$"))  {$results=$results + "$Nrecord|6|B|Category`r"}
if (($ary[6])    -and ($ary[6].length -gt 10))       {$results=$results + "$Nrecord|7|A|String length`r"}
if (($ary[7])    -and ($ary[7] -notmatch "^[0-9]{8}$"))  {$results=$results + "$Nrecord|8|C|Date`r"}
if (($ary[8])    -and ($ary[8] -notmatch "^[0-9]{8}$"))  {$results=$results + "$Nrecord|9|C|Date`r"}
if (($ary[9])    -and ($ary[9] -notmatch "^.{2}$"))  {$results=$results + "$Nrecord|10|B|Category`r"}
if (($ary[10])   -and ($ary[10] -notmatch "^.{2}$"))     {$results=$results + "$Nrecord|11|B|Category`r"}
if (($ary[11])   -and ($ary[11] -notmatch "^.{2}$"))     {$results=$results + "$Nrecord|12|B|Category`r"}
if (($ary[12])   -and ($ary[12] -notmatch "^.{2}$"))     {$results=$results + "$Nrecord|13|A|Category`r"}
if (($ary[13])   -and ($ary[13].length -gt 10))      {$results=$results + "$Nrecord|14|A|String length`r"}
if (($ary[14])   -and ($ary[14].length -gt 10))      {$results=$results + "$Nrecord|15|A|String length`r"}
if (($ary[16])   -and ($ary[16].length -gt 10))      {$results=$results + "$Nrecord|17|A|String length`r"}
if (($ary[18])   -and ($ary[17].length -gt 4))       {$results=$results + "$Nrecord|19|A|String length`r"}
if (($ary[26])   -and ($ary[26].length -gt 10))      {$results=$results + "$Nrecord|27|A|String length`r"}
if (($ary[27])   -and ($ary[27].length -gt 10))      {$results=$results + "$Nrecord|28|A|String length`r"}
if (($ary[29])   -and ($ary[29].length -gt 10))      {$results=$results + "$Nrecord|30|A|String length`r"}
if (($ary[30])   -and ($ary[30] -notmatch "^[01]{1}$"))  {$results=$results + "$Nrecord|31|B|Category`r"}
$results.TrimEnd("`r") | out-file -filepath "..." -append
}

Вы можете сделать шаг назад и потратить немного времени, чтобы изучить основы Powershell с нуля. Я думаю, что SO не может шаг за шагом научить вас писать сценарии.

Olaf 02.02.2019 21:44

Согласитесь с Олафом в этом вопросе и проголосуйте за то, чтобы закрыть или отложить, а не за широкое. Тем не менее, пользователь 5489286, используйте это обсуждение, чтобы узнать, что вам нужно знать, и как атаковать его шаг за шагом. reddit.com/r/PowerShell/comments/afqmmw/…

postanote 02.02.2019 22:37

Добро пожаловать в PowerShell. Мне нравится, что вы просите оставить отзыв. Использование отзывов от людей, которые написали больше Posh, — это профессиональный ход. Вы получите меньше статики, опубликовав это на codereview.stackexchange.com; говорю вам для справки.

Adam 03.02.2019 00:08

Я думаю, что на $ary[12] опечатка. Разве результат не должен быть "$Nrecord|13|B|Category" (B вместо A)?

Theo 03.02.2019 11:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
63
2

Ответы 2

Допустим, у вас есть CSV-файл с именем sample.csv, который выглядит следующим образом:

1,lori renier,shark
2,marc cuban,shark
3,adam,tuna
4,Olaf,Chubb

Я бы загрузил данные чем-то вроде...

$contents = Import-CSV -Path .\sample.csv -Delimiter ',' -Header @('id','name','type')

Затем я просматривал содержимое, делая все, что мне нужно было сделать...

foreach ($record in $contents) {
    if ($record.id.length -eq '') { $record.id = ... }
    if ($record.name -eq '') { $record.name = ... }
    if ($record.type -eq '') { $record.type = ... }
}

Затем я бы экспортировал чистые результаты...

Export-CSV -Path .\clean.csv -Delimiter ',' -Encoding 'ASCII' -NoTypeInformation -Append

Методы/объекты .NET обычно быстрее. Таким образом, использование [System.IO.File]::ReadLines("..."), вероятно, будет работать немного лучше, но люди Powershell обычно сначала смещают доступные командлеты, прежде чем вернуться к коду .NET.

Я не уверен, что это сильно вам поможет, но вы можете создать две небольшие функции тестирования, чтобы несколько упростить код. Кроме того, вместо того, чтобы выполнять так много конкатенаций строк ($results=$results + ...), я думаю, что использование объекта Stringbuilder будет работать намного лучше.

function Test-Length ([string]$value,[int]$size) {
    return (!([string]::IsNullOrEmpty($value)) -and $value.Length -gt $size) 
}

function Test-NotMatch([string]$value,[string]$regex) {
    return (!([string]::IsNullOrEmpty($value)) -and $value -notmatch $regex)
}

$Nrecord = 0
# use a StringBuilder object for better performance
$results = New-Object -TypeName 'System.Text.StringBuilder'
foreach ($record in [System.IO.File]::ReadLines("...")) {
    $ary=$record.split('|')
    $Nrecord++
    # $i is the array index counter that makes it easier to write the result
    $i = 0

    if (Test-Length $ary[$i++] 50)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-Length $ary[$i++] 50)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-NotMatch $ary[$i++] "^[012]{1}$") {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    $i++     # skipping element 3. Not important?
    if (Test-NotMatch $ary[$i++] "^[0-9]{2}$") {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-NotMatch $ary[$i++] "^[123]{1}$") {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-NotMatch $ary[$i++] "^[0-9]{8}$") {[void]$results.AppendLine("$Nrecord|$i|C|Date")}
    if (Test-NotMatch $ary[$i++] "^[0-9]{8}$") {[void]$results.AppendLine("$Nrecord|$i|C|Date")}
    if (Test-NotMatch $ary[$i++] "^.{2}$")     {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-NotMatch $ary[$i++] "^.{2}$")     {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-NotMatch $ary[$i++] "^.{2}$")     {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-NotMatch $ary[$i++] "^.{2}$")     {[void]$results.AppendLine("$Nrecord|$i|B|Category")}
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    $i++    # skipping element 15. Not important?
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    $i++    # skipping element 17. Not important?
    if (Test-Length $ary[$i++] 4)              {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    $i = 26 # skipping elements 19 to 25. Not important?
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    $i++    # skipping element 28. Not important?
    if (Test-Length $ary[$i++] 10)             {[void]$results.AppendLine("$Nrecord|$i|A|String length")}
    if (Test-NotMatch $ary[$i++] "^[01]{1}$")  {[void]$results.AppendLine("$Nrecord|$i|B|Category")}

    Add-Content -Path "..." -Value $results.ToString()
    # we're reusing the stringbuilder for the next iteration
    [void]$results.Clear()
}

Для этого решения я ожидал, что $i будет увеличиваться каждый раз, когда он используется в качестве значения индекса ($ary[$i++]), но это не так. Это поведение необходимо включить в моем экземпляре?

DAWG 04.02.2019 20:47

@DAWG А? Я не могу это воспроизвести. Переменная индекса $i увеличивается, как и ожидалось, во всех моих тестовых примерах. Вы можете проверить это, написав много Write-Host "Index now: $i" перед каждым if (...) или временно заставить функции всегда возвращать $true, а затем посмотреть на второй столбец в выводе $results.ToString().

Theo 05.02.2019 11:00

@DAWG Кроме того, в вашем примере кода вы пропускаете элементы массива 17, 19, 20, 21, 22, 23, 24, 25 и 28. Это сделано по какой-то причине или просто по недосмотру?

Theo 05.02.2019 11:05

Другие вопросы по теме