none
Using PowerShell with RegEx to batch rename files with rearrangement and substrings RRS feed

  • Question

  • New to PowerShell since a couple weeks ago, and am loving the regex support and piping from cmdlets... Looking for a way to rename PDF files from this pattern:

    News October 2015.pdf

    Old Headlines October 2015.pdf

    to this pattern:

    News Oct 2015.pdf

    Old Headlines Oct 2015.pdf

    To accomplish this I have tried to use a regex to capture a word that is a valid English month name only, then replace with an abbreviated version of it. But

    $newName = $newName -replace '([ADFJMNOS][aceopu][bcglnrtvy][a-z]*\s)','$1.substring(0,3)'

    does not compute the substring, rather outputs "October .substring(0,3)2015"

    Various other attempts have also failed.

    Is there a way to use $newName.Replace() to do what I need, or another trick I am missing to make the first instance work?

    Wednesday, November 11, 2015 4:22 AM

Answers

  • Personally I'd just go with the ability to chain renames:

    $OldStr = "Old Headlines October 2015.pdf"
    
    $NewStr = $OldStr.Replace('January','Jan').Replace('February','Feb').Replace('March','Mar').Replace('April','Apr').Replace('June','Jun').Replace('July','Jul').Replace('August','Aug').Replace('September','Sep').Replace('October','Oct').Replace('November','Nov').Replace('December','Dec')
    
    $NewStr


    • Marked as answer by bgracey Friday, November 13, 2015 3:45 AM
    Wednesday, November 11, 2015 1:19 PM
  • Here is a trivial way to do this with a single replace:

    First set up the test data:

    $months='January|February|March|April|May|June|July|August|September|October|November|December'
    
    $filenames=@(
    	"News October 2015.pdf", 
    	"Old Headlines November 2015.pdf"
    )
    
    

    Here is the simple change engine:

    $filenames | % {
    	$month=if($_ -match $months){$matches[0]}
    	$_ -replace $month,$month.SubString(0,3)
    }
    
    Very simple, very neat.


    \_(ツ)_/

    • Marked as answer by bgracey Friday, November 13, 2015 3:45 AM
    Thursday, November 12, 2015 5:37 AM

All replies

  • Hi Bgracey,

    You are getting it too complex.

    Simple Replace on the old variable is enough.

    Try this.

    $OldStr = "Old Headlines October 2015.pdf"
    
    $NewStr = $OldStr.Replace("October","Oct")
    
    $NewStr

    for execution you need to do this: Use $() and double quotes.

    "$($1.substring(0,3))"


    Regards,

    Satyajit

    Please“Vote As Helpful” if you find my contribution useful or “MarkAs Answer” if it does answer your question. That will encourage me - and others - to take time out to help you.



    • Edited by Satyajit321 Wednesday, November 11, 2015 7:23 AM
    Wednesday, November 11, 2015 7:15 AM
  • Thank you for the suggestions Satyajit.  I want to use a regular expression to match the month name because of course, the months will change.  I could use 12 different $string.Replace() methods but I thought there should be a way to combine regex and substring to abbreviate whichever month the filename contains using one line of code.

    I tried the "$($1.subtring(0,3))" line thus:

    $newName = $newName.Replace("([ADFJMNOS][aceopu][bcglnrtvy][a-z]*\s)","$($1.substring(0,3))")

    But all I get is "You cannot call a method on a multi-valued expression."  I'm not sure how to avoid a multi-valued expression for this, but I'll keep trying.

    Wednesday, November 11, 2015 1:08 PM
  • Personally I'd just go with the ability to chain renames:

    $OldStr = "Old Headlines October 2015.pdf"
    
    $NewStr = $OldStr.Replace('January','Jan').Replace('February','Feb').Replace('March','Mar').Replace('April','Apr').Replace('June','Jun').Replace('July','Jul').Replace('August','Aug').Replace('September','Sep').Replace('October','Oct').Replace('November','Nov').Replace('December','Dec')
    
    $NewStr


    • Marked as answer by bgracey Friday, November 13, 2015 3:45 AM
    Wednesday, November 11, 2015 1:19 PM
  • $_ -replace 'January|february|march|april....', '$1???'

    If you can state the transform on the $1 then you can do it in one replace.


    \_(ツ)_/

    Wednesday, November 11, 2015 2:49 PM
  • Thanks jrv,

    I've been trying to do just that, I think. Can you clarify? I tried $newName = $newName -replace 'regex_pattern','$1.substring(0,3)' to no avail. Did I misunderstand what you're suggesting?



    • Edited by bgracey Wednesday, November 11, 2015 11:24 PM
    Wednesday, November 11, 2015 11:18 PM
  • Personally I'd just go with the ability to chain renames:

    $OldStr = "Old Headlines October 2015.pdf"
    
    $NewStr = $OldStr.Replace('January','Jan').Replace('February','Feb'). <snipped>

    I didn't know that was possible, but I concede it's probably the easiest solution given the relatively limited number of choices in the data set. Thanks for the suggestion.
    Wednesday, November 11, 2015 11:21 PM
  • As far as I know, in the Microsoft implementation of RegEx, there is no way to do that.  We can, however, use a custom RegEx and define a custom method for handling replacements.


    \_(ツ)_/

    Wednesday, November 11, 2015 11:22 PM
  • Thanks for the link jrv.  I'm afraid it still leaves me at a loss, but it's good learning just the same.I did some further searching and came across this

    http://powershell.com/cs/forums/t/13515.aspx

    which led to another attempt:

    $String = "AABBAASSAA November 2015 May July 2015 August "
    $Pattern = "([ADFJMNOS][aceopu][bcglnrtvy][a-z]*\s)"
    [scriptblock]$Eval = {write-output $1.substring(0,3)}
    [regex]::Replace($String,$Pattern,$Eval)

    which begets "You cannot call a method on a null-valued expression".

    I don't understand enough about the available variables and such, it seems to come up with a solution.

    Thursday, November 12, 2015 2:51 AM
  • Here's a different approach using -split. Should work as long as your file name format stays the same.

    "News October 2015.pdf", "Old Headlines October 2015.pdf" | 
    % {
        $FileParts = $_ -split ' '
        Switch ($FileParts.Count) {
            3 {$FileParts[1] = $FileParts[1].Substring(0,3)}
            4 {$FileParts[2] = $FileParts[2].Substring(0,3)}
        }
        $FileParts -join " "
    }
    

    Results:

    News Oct 2015.pdf
    Old Headlines Oct 2015.pdf

    Thursday, November 12, 2015 4:00 AM
  • And here is a way to do it with RegEx and -replace

    "Old Headlines October 2015.pdf" -replace "^(.* )(\w\w\w)(.+)( \d\d\d\d.pdf)$", "`$1`$2`$4"
    "News October 2015.pdf" -replace "^(.* )(\w\w\w)(.+)( \d\d\d\d.pdf)$", "`$1`$2`$4"

    Results:

    Old Headlines Oct 2015.pdf
    News Oct 2015.pdf

    Thursday, November 12, 2015 4:45 AM
  • Here is a trivial way to do this with a single replace:

    First set up the test data:

    $months='January|February|March|April|May|June|July|August|September|October|November|December'
    
    $filenames=@(
    	"News October 2015.pdf", 
    	"Old Headlines November 2015.pdf"
    )
    
    

    Here is the simple change engine:

    $filenames | % {
    	$month=if($_ -match $months){$matches[0]}
    	$_ -replace $month,$month.SubString(0,3)
    }
    
    Very simple, very neat.


    \_(ツ)_/

    • Marked as answer by bgracey Friday, November 13, 2015 3:45 AM
    Thursday, November 12, 2015 5:37 AM
  • Thanks jrv, that last suggestion is simple and elegant, and would work well for other abbreviation tasks with slight modification.

    Thanks to all who posted suggestions, I have got it working with all my test file names at the moment, so things are looking up.

    Friday, November 13, 2015 3:50 AM