1

I have a series of files all named something like:

PRT14_WD_14220000_1.jpg

I need to add two zeroes after the last underscore and before the number so it looks like PRT14_WD_14220000_001.jpg

I've tried"

(dir) | rename-Item -new { $_.name -replace '*_*_*_','*_*_*_00' }

Appreciate any help.

3 Answers3

0

the following presumes your last part of the .BaseName will always need two zeros added to it. what it does ...

  • fakes getting the fileinfo object that you get from Get-Item/Get-ChildItem
    replace that with the appropriate cmdlet. [grin]
  • splits the .BaseName into parts using the _ as the split target
  • adds two zeros to the final part from the above split
  • merges the parts into a $NewBaseName
  • gets the .FullName and replaces the original BaseName with the $newBaseName
  • displays that new file name

you will still need to do your rename, but that is pretty direct. [grin]

here's the code ...

# fake getting a file info object
#    in real life, use Get-Item or Get-ChildItem
$FileInfo = [System.IO.FileInfo]'PRT14_WD_14220000_1.jpg'

$BNParts = $FileInfo.BaseName.Split('_')
$BNParts[-1] = '00{0}' -f $BNParts[-1]
$NewBasename = $BNParts -join '_'

$NewFileName = $FileInfo.FullName.Replace($FileInfo.BaseName, $NewBaseName)

$NewFileName

output = D:\Data\Scripts\PRT14_WD_14220000_001.jpg

Lee_Dailey
  • 7,292
  • 2
  • 22
  • 26
0

The closest thing to what you attempted would be this. In regex, the wildcard is .*. And the parentheses do grouping to refer to later with the dollar sign numbers.

dir *.jpg | rename-Item -new { $_.name -replace '(.*)_(.*)_(.*)_','$1_$2_$3_00' } -whatif

What if: Performing the operation "Rename File" on target "Item: C:\users\admin\foo\PRT14_WD_14220000_1.jpg Destination: C:\users\admin\foo\PRT14_WD_14220000_001.jpg".

Ok, here's my take when you want the number with max two zeroes padding. $num has to be an integer for the .tostring() method I want.

dir *.jpg | rename-item -newname { $a,$b,$c,$num = $_.basename -split '_'
  $num = [int]$num
  $a + '_' + $b + "_" + $c + '_' + $num.tostring('000') + '.jpg'
} -whatif

js2010
  • 23,033
  • 6
  • 64
  • 66
  • This works. Thank you. Follow up question, the end of my names always needs to be 3 characters. How would I handle this if my starting integer at the end is two digits? I would have some files with one digit and others with two. So if it starts as '_11.jpg' I will need it to be '_011.jpg', but if it was '_5.jpg' I would need it to be '_005.jpg'? – user12520924 Dec 11 '19 at 22:36
  • I would do it in a completely different way with -split and .tostring(). Could you add that to the question? – js2010 Dec 11 '19 at 22:51
0

The -replace operator operates on regexes (regular expressions), not wildcard expressons such as * (by itself), which is what you're trying to use.

A conceptually more direct approach is to focus the replacement on the end of the string:

Get-ChildItem | # `dir` is a built-in alias for Get-ChildItem`
  Rename-Item -NewName { $_.Name -replace '(?<=_)[^_]+(?=\.)', '00$&' } -WhatIf

Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

  • (?<=_)[^_]+(?=\.) matches a nonempty run (+) of non-_ chars. ([^_]) preceded by _ ((?<=_) and followed by a literal . ((?=\.)), excluding both the preceding _ and the following . from what is captured by the match ((?<=...) and (?=...) are non-capturing look-around assertions).

    • In short: This matches and captures the characters after the last _ and before the start of the filename extension.
  • 00$& replaces what was matched with 00, followed by what the match captured ($&).


In a follow-up comment you mention wanting to not just blindly insert 00, but to 0-left-pad the number after the last _ to 3 digits, whatever the number may be.

In PowerShell [Core] 6.1+, this can be achieved as follows:

Get-ChildItem |
  Rename-Item -NewName { 
    $_.Name -replace '(?<=_)[^_]+(?=\.)', { $_.Value.PadLeft(3, '0') } 
  } -WhatIf
  • The script block ({ ... }) as the replacement operand receives each match as a Match instance stored in automatic variable $_, whose .Value property contains the captured text.

  • Calling .PadLeft(3, '0') on that captured text 0-left-pads it to 3 digits and outputs the result, which replaces the regex match at hand.

A quick demonstration:

PS> 'PRT14_WD_14220000_1.jpg' -replace '(?<=_)[^_]+(?=\.)', { $_.Value.PadLeft(3, '0') }
PRT14_WD_14220000_001.jpg # Note how '_1.jpg' was replaced with '_001.jpg'

In earlier PowerShell versions, you must make direct use of the .NET [regex] type's .Replace() method, which fundamentally works the same:

Get-ChildItem |
  Rename-Item -NewName { 
    [regex]::Replace($_.Name, '(?<=_)[^_]+(?=\.)', { param($m) $m.Value.PadLeft(3, '0') }) 
  } -WhatIf

mklement0
  • 382,024
  • 64
  • 607
  • 775