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