13

I have filenames in following format:

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

I need to sort according to following rules: first by middle part, then by name, in natural order (i.e. foobar10 > foobar2). I don't know prefix value, but I know the separator (dash).

so my first attempt, naturally:

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

This has a problem that the suffix affects order (ignore-aaa-1ignore-wname) is sorted before ignore-aaa-2ignore-aname), so:

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

Ok, that sorts by the middle but already unwhieldy. If I'm to add natural sort that would be even worse. What's more elegant way of doing that?

2 Answers 2

15

I understand the task in this way: sorting should be performed by 3 expressions: 1) middle part, 2) name part without digits, 3) number represented by trailing digits of the name part.

Let’s create these expressions with regular expressions. Here is the answer:

# 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

For better understanding of how it works you may test these expressions separately:

$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

As a result, for example, these files (extension is not important):

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

will be sorted like:

ignore-aaa-1ignore-wname2.txt
ignore-aaa-1ignore-wname10.txt
aaa-zzz-1ignore-wname2.txt
aaa-zzz-1ignore-wname10.txt
Sign up to request clarification or add additional context in comments.

2 Comments

"$part1, $part2, $part2" should be "$part1, $part2, $part3" thanks!
Yes, I have noticed that, too. Fixed.
1

Does this do it?

 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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.