Search code examples
powershelldesign-patternsreplaceforeachget-childitem

Powershell script to replace pattern YY to YYYY


I am not the Powershell pro so I need some help.

What I have now is for example:

somelongname_08-01-01_someotherlongname.pdf

and I want a rename to

somelongname_2008-01-01_someotherlongname.pdf

In short changing two digit year format to four digit year format within the name of multiple files.

At the moment I use the following script to rename all files in a specific folder:

get-childitem *.* | foreach { rename-item $_ $_.Name.Replace("_08-", "_2008-") }

I do not want to achieve it by copying the above formula to:
...
get-childitem *.* | foreach { rename-item $_ $_.Name.Replace("_08-", "_2008-") }
get-childitem *.* | foreach { rename-item $_ $_.Name.Replace("_09-", "_2009-") }
get-childitem *.* | foreach { rename-item $_ $_.Name.Replace("_10-", "_2010-") }
...

So is there a more elegant and fast way, because the years may vary from +- 1925-2023

The basic search and replace pattern is always the same and its's unique in each filename and begins with _ contains two numbers for the year and ends with -.

So I have two cases
-) years from 25 to 99 need at the beginning an "19"
-) years from 00 to 23 need at the beginning an "20"



Thanks in advance


Solution

  • You can use Regex.Replace(String, String, MatchEvaluator) to handle the logic if 20 or 19 should be prepended to the string, for example:

    $re = [regex] '(?<=_)\d{2}(?=-)'
    
    'somelongname_08-01-01_someotherlongname.pdf',
    'somelongname_25-01-01_someotherlongname.pdf',
    'somelongname_24-01-01_someotherlongname.pdf' | ForEach-Object {
        $re.Replace($_, {
            switch($args[0].Value) {
                { $_ -ge 25 -and $_ -le 99 } {
                    return '19' + $_
                }
                { $_ -ge 0 -and $_ -le 23 } {
                    return '20' + $_
                }
                # leave it as-is if it didn't match the above conditions
                Default { $_ }
            }
        })
    }
    

    If this is what you were looking for, you can include it to your Rename-Item:

    $re = [regex] '(?<=_)\d{2}(?=-)'
    
    Get-ChildItem -Filter *.pdf | Rename-Item -NewName {
        $re.Replace($_.Name, {
            switch($args[0].Value) {
                { $_ -ge 25 -and $_ -le 99 } {
                    return '19' + $_
                }
                { $_ -ge 0 -and $_ -le 23 } {
                    return '20' + $_
                }
                Default { $_ }
            }
        })
    }