2010-11-10 11 views
12

Je suis nouveau à l'alimentation shell.tri personnalisé dans PowerShell

Mon problème est que j'ai les noms de fichiers en format suivant:

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

J'ai besoin de trier selon les règles suivantes: tout d'abord par partie centrale, puis par nom, dans l'ordre naturel (c.-à-foobar10> foobar2) . Je ne connais pas la valeur du préfixe, mais je connais le séparateur (tiret).

donc ma première tentative, naturellement:

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

Cela a un problème que le suffixe affecte l'ordre (ignore-aaa-1ignore-wname) est trié avant d'ignorer-aaa-2ignore-aname), donc:

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

Ok, cela se trie par le milieu, mais déjà non-maniable. Si je devais ajouter un genre naturel, ce serait encore pire. Quoi de plus élégant moyen de le faire?

Répondre

11

Je comprends la tâche de cette manière: le tri doit être effectué par 3 expressions: 1) partie médiane, 2) nom partie sans chiffres, 3) nombre représenté par les chiffres de fin de la partie nom. Créons ces expressions avec des expressions régulières.

Voici la réponse:

# 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 

Pour une meilleure compréhension de la façon dont il fonctionne, vous pouvez tester ces expressions séparément:

$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 

En conséquence, par exemple, ces fichiers (extension n'est pas important):

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

seront triés comme:

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

"$ part1, $ part2, $ part2" devrait être "$ part1, $ part2, $ part3" merci! – DennyRolling

+0

Oui, je l'ai remarqué aussi. Fixé. –

Questions connexes