Home > Mobile >  Powershell script to replace pattern YY to YYYY
Powershell script to replace pattern YY to YYYY

Time:12-01

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

CodePudding user response:

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 { $_ }
        }
    })
}

CodePudding user response:

Normally, the century that is chosen will depend on the half-century year, so if the two-digit year is 50, this will be regarded as 1950 and anything below 50 will become 20xx

You can use .Net for this:

(Get-ChildItem -Path 'D:\Test' -Filter '*_*_*.pdf' -File) | ForEach-Object { 
    # split the file BaseName in three parts
    $prefix, $date, $postfix = $_.BaseName -split '_', 3
    # let .Net parse out the date. 
    # Up to and including year 49, this century is used, year 50 and above will become the 1900's
    $date = [datetime]::ParseExact($date,'yy-MM-dd', $null)
    $newName = '{0}_{1:yyyy-MM-dd}_{2}{3}' -f $prefix, $date, $postfix, $_.Extension
    $_ | Rename-Item -NewName $newName
}

Result:

somelongname_08-01-01_someotherlongname.pdf --> somelongname_2008-01-01_someotherlongname.pdf
somelongname_25-01-01_someotherlongname.pdf --> somelongname_2025-01-01_someotherlongname.pdf
somelongname_49-01-01_someotherlongname.pdf --> somelongname_2049-01-01_someotherlongname.pdf
somelongname_50-01-01_someotherlongname.pdf --> somelongname_1950-01-01_someotherlongname.pdf

If however you have good reason to deviate from this, you can do:

(Get-ChildItem -Path 'D:\Test' -Filter '*_*_*.pdf' -File) | ForEach-Object { 
    # split the file BaseName in three parts
    $prefix, $date, $postfix = $_.BaseName -split '_', 3
    $century = if ([int]$date.Substring(0,2) -ge 25) { 19 } else { 20 }
    $newName = '{0}_{1}{2}_{3}{4}' -f $prefix, $century, $date, $postfix, $_.Extension
    $_ | Rename-Item -NewName $newName
}

Result now:

somelongname_08-01-01_someotherlongname.pdf --> somelongname_2008-01-01_someotherlongname.pdf
somelongname_25-01-01_someotherlongname.pdf --> somelongname_1925-01-01_someotherlongname.pdf
somelongname_49-01-01_someotherlongname.pdf --> somelongname_1949-01-01_someotherlongname.pdf
somelongname_50-01-01_someotherlongname.pdf --> somelongname_1950-01-01_someotherlongname.pdf
  • Related