Первый раз пишу PS скрипт. Предполагается, что источником являются данные, разделенные вертикальной чертой, которые соответствуют некоторым ограничениям. Этот скрипт предназначен для выявления записей в источнике, которые нарушают некоторые правила. Я в основном использовал документацию Microsoft, чтобы узнать достаточно, чтобы добраться до этого момента.
Вопросы:
Спасибо
$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
}
Согласитесь с Олафом в этом вопросе и проголосуйте за то, чтобы закрыть или отложить, а не за широкое. Тем не менее, пользователь 5489286, используйте это обсуждение, чтобы узнать, что вам нужно знать, и как атаковать его шаг за шагом. reddit.com/r/PowerShell/comments/afqmmw/…
Добро пожаловать в PowerShell. Мне нравится, что вы просите оставить отзыв. Использование отзывов от людей, которые написали больше Posh, — это профессиональный ход. Вы получите меньше статики, опубликовав это на codereview.stackexchange.com; говорю вам для справки.
Я думаю, что на $ary[12] опечатка. Разве результат не должен быть "$Nrecord|13|B|Category" (B вместо A)?





Допустим, у вас есть 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 А? Я не могу это воспроизвести. Переменная индекса $i увеличивается, как и ожидалось, во всех моих тестовых примерах. Вы можете проверить это, написав много Write-Host "Index now: $i" перед каждым if (...) или временно заставить функции всегда возвращать $true, а затем посмотреть на второй столбец в выводе $results.ToString().
@DAWG Кроме того, в вашем примере кода вы пропускаете элементы массива 17, 19, 20, 21, 22, 23, 24, 25 и 28. Это сделано по какой-то причине или просто по недосмотру?
Вы можете сделать шаг назад и потратить немного времени, чтобы изучить основы Powershell с нуля. Я думаю, что SO не может шаг за шагом научить вас писать сценарии.