Reputation: 33
I've been using Powershell to simplify repetitive tasks in creating directories, renaming and moving files. I'm working with Video and PDF files where the required syntax of the filename is very specific. So far I've been able to correct all of the common errors I run across, but this one has me stumped.
The correct syntax for my files would include:
01A-50_02A-50-CIPP-PRE.MP4
01AA-50_02AA-50-CIPP-PNSL.PDF
W01AA-48_02AA-48-CIPP-PST-CMP.MPG
I'm receiving a large amount of files that look like this:
01A-50-02A-50-CIPP-PRE.MP4
01AA-50-02AA-50-CIPP-PNSL.PDF
W01AA-48-02AA-48-CIPP-PST-CMP.MPG
I need to replace the second dash with an underscore while keeping the other dashes unaffected. I can otherwise do this in bulk with some help from excel, but I was hoping to have a short code that could find and correct this error in syntax without having to export a list to excel, use text to columns, and then concatenate the alphanumeric portions back together. I also don't want to correct all these filenames manually.
From what I've researched, it's not possible to target a specific occurrence of a character to replace. the closest I've come to thinking I'd found a solution involved REGEX and identifying and replacing a pattern. I haven't been able to do anything constructive with that.
The way I would use this code would be by opening the folder that contains the missnamed files, opening a Powershell window there, copying the code from a txt file on my desktop, and pasting it into Powershell.
Any help on this would be greatly appreciated.
Upvotes: 2
Views: 2459
Reputation: 33
Thank you Solomon Ucko! That was almost exactly what I was looking for.
Get-ChildItem | Rename-Item -NewName {$.name -replace '(?<=(^|\n)[^-]*-[^-]*)-',''}
It worked great on all of the examples I could throw at it, EXCEPT... if I ran the code on a mixed group of misnamed and properly named files, it would add another underscore where it didn't belong...
"E21U-50A_E21U_50-CIPP-PST-CMP"
instead of
"E21U-50A_E21U-50-CIPP-PST-CMP"
the fix for that was easy enough.
All I did was replace all _
s with -
s, first.
Get-ChildItem | Rename-Item -NewName {$_.name -replace '_','-'}
Get-ChildItem | Rename-Item -NewName {$_.name -replace '(?<=(^|\n)[^-]*-[^-]*)-','_'}
Thanks to everyone who had other ideas. Admittedly I have not tried them because this solution was the first one I tried and it did the trick.
I am, however, going to tinker with the other solutions after I get my work done.
Thanks again.
Upvotes: 1
Reputation: 439267
Use the -replace
operator with a regular expression:
Get-ChildItem |
Rename-Item -NewName { $_.Name -replace '^([^_-]+-[^_-]+)-', '$1_' } -WhatIf
-WhatIf
previews the renaming operation; remove it to perform actual renaming.
Regex '^([^_-]+-[^_-]+)-'
captures the first two -
separated tokens at the start (^
) of the filename, using a capture group ((...)
) to capture the tokens excluding the 2nd -
.
[^_-]+
captures any nonempty run of characters that are neither -
nor _
. _
is also ruled out in order to prevent false positives with filenames that already are correct; for those, not ruling out _
would match the first 3 tokens and insert an additional _
there.Replacement operand $1_
then uses the value of the 1st (and only) capture group ($1
) followed by a literal _
to replace what the regex matched, which effectively replaces the 2nd -
with a _
.
If a given file name doesn't match the regex (if it already is correct), the name is returned as-is, which is a quiet no-op in the context of Rename-Item
.
Upvotes: 4
Reputation: 6109
What about this RegEx: (?<=(^|\n)[^-]*-[^-]*)-
?
Or as a full command (using answers to Replace Part of File Name Powershell):
Get-ChildItem | Rename-Item -NewName {$_.name -replace '(?<=^[^-_]+-[^-_]+)-','_'}
Edit: incorporated suggestions from @mklement0
Upvotes: 1
Reputation: 174700
You could split the string on the first two occurrences of -
, then concatenate them by -
and _
:
$name = '01A-50-02A-50-CIPP-PRE.MP4'
$first,$second,$rest = $name -split '-',3
$newName = "${first}-${second}_${rest}"
Upvotes: 1
Reputation: 4020
Looking at your examples, it appears that the second -
always appears between numbers. Something like $Variable -replace 'REGEX','_'
Using the below regex will match those.
(?<=[0-9])(.)(?=[0-9])
()
creates a group to match, it is a capturing group.
?<=
is a positive lookbehind, it matches a group before the main expression without including it in the results
[0-9]
is the character set, matching anything between 0 and 9.
.
matches any character except line breaks
?=
is a positive lookahead, it matches a group after the main expression without including it in the results
I recommend using Regexr to test and learn Regex.
Upvotes: 1