2010-11-10 6 views
12

Я новичок в силовой оболочке.custom sorting in powershell

Моя проблема заключается в том, что у меня есть имена файлов в следующем формате:

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

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

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

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

Это проблема, что суффикс влияет на порядок (игнорировать-ааа-1ignore-wname) сортируют, прежде чем игнорировать-ааа-2ignore-aname), так что:

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

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

ответ

11

Я понимаю задачу следующим образом: сортировка должна выполняться тремя выражениями: 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 
+0

«$ part1, $ part2, $ part2» должно быть «$ part1, $ part2, $ part3» спасибо! – DennyRolling

+0

Да, я тоже это заметил. Исправлена. –