Подтвердить что ты не робот

Пользовательская сортировка в powershell

У меня есть имена файлов в следующем формате:

[ignore-prefix]-[important-middle]-[ignore-suffix]-[name-with-digits]

Мне нужно отсортировать по следующим правилам: сначала по средней части, затем по имени, в естественном порядке (т.е. foobar10> foobar2). Я не знаю значения префикса, но я знаю разделитель (тире).

поэтому моя первая попытка, естественно:

 filelist | Sort-Object -property @{Expression='
       {$_.FullName.SubString($_.FullName.IndexOf("-")+1)}}

При этом возникает проблема, связанная с тем, что суффикс влияет на порядок (ignore-aaa-1ignore-wname) сортируется перед ignore-aaa-2ignore-aname), поэтому:

 $filelist | Sort-Object -property @{Expression='
       {$_.FullName.SubString($_.FullName.IndexOf("-")+1,'
        $_.FullName.SubString($_.FullName.IndexOf("-")+1).IndexOf("-"))}}

Хорошо, что-то вроде середины, но уже громоздко. Если бы я добавил натуральную сортировку, это было бы еще хуже. Какой более элегантный способ сделать это?

4b9b3361

Ответ 1

Я понимаю задачу следующим образом: сортировка должна выполняться тремя выражениями: 1) средняя часть, 2) имя части без цифр, 3) число, представленное завершающими цифрами части имени.

Позволяет создавать эти выражения с помощью регулярных выражений. Вот ответ:

# gets the middle part
$part1 = { if ($_.Name -match '^[^-]+-([^-]+)') { $matches[1] } }

# gets the name part with no digits
$part2 = { if ($_.Name -match '^[^-]+-[^-]+-[^-]+-(\D+)') { $matches[1] } }

# gets the number represented by digits from name (cast to [int]!)
$part3 = { if ($_.Name -match '^[^-]+-[^-]+-[^-]+-\D+(\d+)') { [int]$matches[1] } }

# sort it by 3 expressions
$filelist | Sort-Object $part1, $part2, $part3

Для лучшего понимания того, как это работает, вы можете тестировать эти выражения отдельно:

$part1 = { if ($_.Name -match '^[^-]+-([^-]+)') { $matches[1] } }
$part2 = { if ($_.Name -match '^[^-]+-[^-]+-[^-]+-(\D+)') { $matches[1] } }
$part3 = { if ($_.Name -match '^[^-]+-[^-]+-[^-]+-\D+(\d+)') { [int]$matches[1] } }

Write-Host '----- test1'
$filelist | % $part1

Write-Host '----- test2'
$filelist | % $part2

Write-Host '----- test3'
$filelist | % $part3

В результате, например, эти файлы (расширение не важно):

aaa-zzz-1ignore-wname10.txt
aaa-zzz-1ignore-wname2.txt
ignore-aaa-1ignore-wname10.txt
ignore-aaa-1ignore-wname2.txt

будет сортироваться следующим образом:

ignore-aaa-1ignore-wname2.txt
ignore-aaa-1ignore-wname10.txt
aaa-zzz-1ignore-wname2.txt
aaa-zzz-1ignore-wname10.txt

Ответ 2

Это делает это?

 ls | sort { ($_ -split '-')[1] }

       Directory: C:\users\js\foo


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        7/22/2019   5:20 PM             10 pre-aaa-zuf-joe111
-a----        7/22/2019   5:20 PM             10 bre-aab-suf-joe112
-a----        7/22/2019   5:20 PM             10 pre-aac-auf-joe113