2

I have a regular expression defined as follows:

$regexpo = "^Amma\s(?'version'(\d+\.){3}\d)\.zip$"

The above expression has label attached with a group - (\d+.){3}\d)

And I am using it as follows:

$Library =  $wholeContent | 
  Where-Object { $_.Name -match $regexpo } | 
    Sort-Object Name -Descending

But I want to sort it by the labelled group within the defined regular expression instead, which represents a version number.

mklement0
  • 382,024
  • 64
  • 607
  • 775
sajis997
  • 1,089
  • 1
  • 15
  • 29

2 Answers2

2

Use Sort-Object with a calculated property (a script block ({ ... }) that is evaluated for each input object, reflected in $_) as follows:

# Sample input
$wholeContent = 
  [pscustomobject] @{ Name = 'Amma 10.0.0.1.zip'; Type = '...' },
  [pscustomobject] @{ Name = 'Not a match' ; Type = '...' },
  [pscustomobject] @{ Name = 'Amma 1.0.0.2.zip' ; Type = '...' },
  [pscustomobject] @{ Name = 'Amma 2.1.2.3.zip' ; Type = '...' }

# Define the regex that matches the full name
# and captures the embedded version number in named capture group 'version'.
# Better to use '...' (single quotes) to define regexes, to prevent
# confusion with string expansion inside "..."
# Note the alternate syntax `<version>` instead of `'version'`.
$regex = '^Amma\s(?<version>(\d+\.){3}\d+)\.zip$'

# Filter by the line of interest, then sort by the extracted version number.
# Automatic variable $Matches is a hashtable that contains the results of
# the regex match, with entry 'version' containing the capture group's value. 
# Casting to [version] ensures that version-appropriate sorting is used.
$wholeContent |
  Where-Object { $_.Name -match $regex } | 
    Sort-Object { [version] ($_.Name -replace $regex, '${version}') }

Note that matching twice is required here[1]: once to filter in the lines of interest, and again to extract the embedded version text, via the -replace operator.

Note: Use of -replace with the original regex here is possible, because the regex at hand is designed to match the whole input string, which allows replacing the whole string with just the named capture group's value (${version}) to yield only the latter; the more verbose alternative is to use another -match operation to obtain the capture-group value via $Matches:
$null = $_.Name -match $regex; $Matches['version']

The above yields the following, showing that only the lines of interest were extracted, properly sorted by version number:

Name              Type
----              ----
Amma 1.0.0.2.zip  ...
Amma 2.1.2.3.zip  ...
Amma 10.0.0.1.zip ...

[1] While the automatic $Matches variable, populated by a -match operation, is available in script blocks in subsequent pipeline segments in principle, allowing access to the results of the matching operation, it cannot be utilized here, because Sort-Object is of necessity an aggregating cmdlet; that is, it must collect all input first in order to perform sorting, at which point using $Matches in the calculated property only contains the last input object's matches.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

Simple example of sorting by a regex match, by the last character.

echo a3 b2 c1 | sort { $_ -match "(?'last'.$)"; $matches.last }                                               

c1
b2
a3
js2010
  • 23,033
  • 6
  • 64
  • 66