0

I have this perl code I am trying to convert to powershell.

foreach my $f ( @file_list ) {
    if( $f =~ /^([\d]+)_${base_ver}_([\d]{4})\.zip$/i ){
        $pfile = $f;
        ( $pnum, $pdate ) = ( $pfile =~ /^([\d]+)_${base_ver}_([\d]{4})\.zip$/i ); # need to convert
        ( $pmon, $pyear ) = ( $pdate =~ /^(\d\d)(\d\d)$/ ); # need to convert
        if( ($patch_nbr == 0) || ($patch_nbr == $pnum) ) {
            $fcnt++;
        }
    }
}

I've converted most of it here..

$file_list = Get-ChildItem -force $base_dir
$file_list | foreach-object {
    if($_ -match "/^([\d]+)_${base_ver}_([\d]{4})\.zip$/i"){
        $pfile = $_


        if($patch_nbr -eq 0 -or $pacth_nbr -eq $pnum){
            $fcnt++
        }
    }
}

Not quite sure how to convert the two variables that equal the regex or if there is a better way to convert the perl code to powershell than what I already have.

2 Answers 2

3

The [mode]/pattern/[replace/][options] syntax from perl doesn't apply to regex in PowerShell.

Thus, your pattern

/^([\d]+)_${base_ver}_([\d]{4})\.zip$/i

becomes

^([\d]+)_${base_ver}_([\d]{4})\.zip$

(i is unnecessary, -match resolves to -imatch (case-insensitive match) by default)


To capture the number prefix and date, you can use a named capture group ((?<name>pattern)):

^(?<num>[\d]+)_${base_ver}_(?<date>[\d]{4})\.zip$

You can then grab the match from $Matches["name"]:

if($f -match "^(?<num>[\d]+)_${base_ver}_(?<date>[\d]{4})\.zip$"){
    $pfile = $f
    $pnum = $Matches["num"]
    $pdate = $Matches["date"]
    $pmon = -join $pdate[0..1]
    $pyear = -join $pdate[2..3]
}

You could also change the regex pattern to capture the month and year individually:

if($f -match "^(?<num>[\d]+)_${base_ver}_(?<month>[\d]{2})(?<year>[\d]{2})\.zip$"){
    $pfile = $f
    $pnum = $Matches["num"]
    $pmon = $Matches["month"]
    $pyear = $Matches["year"]
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Mathias R. Jessen! Helps a lot.
2

I would put a Where-Object filter first. That allows you to use the $matches collection in the subsequent ForEach-Object without a second -match in a nested if statement. If you also change the date pattern from (\d{4}) to (\d{2})(\d{2}) you can assign $pnum, $pmon, and $pyear in a single statement. You could also simplify the condition for incrementing $fcnt. Instead of checking if $patch_nbr equals one of two values you could check if it's contained in an array of the two values.

Get-ChildItem -Force $base_dir |
  Where-Object { $_ -match '^(\d+)_${base_ver}_(\d{2})(\d{2})\.zip$' } |
  ForEach-Object {
    $pnum, $pmon, $pyear = $matches[1..3]
    if (0, $pnum -contains $patch_nbr) { $fcnt++ }
  }
}

Of course, if all you want to do is count the number of files matching a given patch number, you could just do something like this:

$f = Get-ChildItem -Force $base_dir | Where-Object {
       $_ -match '^(\d+)_${base_ver}_\d{4}\.zip$' -and
       0, $matches[1] -contains $patch_nbr
     }
$fcnt = @($f).Count

3 Comments

Thanks for the input Ansgar Wiechers! Saves me an extra line. Also is there a way I can add a ?<date>, so I capture the whole date along with $pnum, $pmon, $pyear?
@marc117 Sure. Simply change (\d{2})(\d{2}) to (?<date>(\d{2})(\d{2})) to get a named group, or to ((\d{2})(\d{2})) to get an additional unnamed group (so you can do the assignment like this: $pnum, $pdate, $pmon, $pyear = $matches[1..4]).
Thanks again @Ansgar Wiechers!

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.