Powershell улучшил производительность и эффективность кодирования, извлекая текст и выводя в файл - PullRequest
0 голосов
/ 02 февраля 2019

Первый раз пишу сценарий 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
}

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Я не уверен, что это вам сильно поможет, но вы могли бы создать две небольшие функции тестирования, чтобы несколько упростить код.Кроме того, вместо того, чтобы делать столько конкатенаций строк ($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()
}
0 голосов
/ 03 февраля 2019

Допустим, у вас есть файл 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-коду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...