3

So I have a list of files in a folder in jpg format like so:

"1.George ABCD.jpg"
"2.George ABCD.jpg"
"3.Mead ABCD.jpg"

So what I want to do is rename them so that the the prefix becomes a suffix like so:

"George ABCD 1.jpg"
"George ABCD 2.jpg"
"Mead ABCD 2.jpg"

and I want to have it work recursively through sub folders.

I have a code segment that I've tried that works here:

ls -Recurse |? BaseName -match '^(\d+\.)([^0-9].*)$' |ren -new {"{0}{1}{2}" -f $matches[2],' ', $matches[1].substring(0,1)+ $_.extension}
cmd /c pause

Now the problem is my piece of code currently doesn't work for double digit names for example:

"11.George ABCD.jpg"

Instead what it does is it spits out

"George ABCD 1.jpg"

which is not what I want, I know it's something to do with the regular expression d+ which is one or more digits, but I'm not sure what I should use instead to make it work properly for one or more digit numbers.

That is I want the output for "11.George ABCD.jpg" to be "George ABCD 11.jpg".

Is there any way I can fix this?

John Smith
  • 333
  • 2
  • 3
  • 9
  • 1
    a non-regex method would be to split the `.BaseName` on the dot, trim the items, join them in the desired order with any desired delimiter, and finally make a file name from them to use in a call to `Rename-Item`. [*grin*] – Lee_Dailey Jul 18 '20 at 13:58

2 Answers2

6

It is because of $matches[1].substring(0,1). You are always only using the first digit of your match. You can get what you want by modifying your first group in your regex and not using substring later:

ls -Recurse |? BaseName -match '^(\d+)\.([^0-9].*)$' |ren -new {"{0}{1}{2}" -f $matches[2],' ', $matches[1] + $_.extension}
stackprotector
  • 10,498
  • 4
  • 35
  • 64
  • Ahhhh yes this was what I was looking for thank you. So it was the regex where I should have shifted the "\." outside of the brackets so it's not part of $matches[1], thank you that makes sense. I was trying to substring because I was including the dot originally as part of $matches[1], but this is a much more elegant solution. – John Smith Jul 18 '20 at 08:30
6

Here is what I would do

Get-ChildItem -File -Recurse | ForEach-Object {
    $newname = $_.Name -replace '^(\d+)\.?\s*(.*)(\.jpg)$', '$2 $1$3'
    if ($newname -ne $_.Name) { $_ | Rename-Item -New $newname }
}

It's not necessarily better than your approach, but it has fewer moving parts and it line-wraps more nicely.

Note the single quotes around the replacement string, they are necessary (otherwise PowerShell will try to grab the $).

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Also works well do you mind if I ask you about the -replace so for '$2 $1$3' is the space necessary in between, does it make any difference? – John Smith Jul 18 '20 at 08:49
  • 1
    @JohnSmith You want a space between the text part of the filename and the number, so yes, the space is necessary. (The `' '` in your `"{0}{1}{2}" -f $matches[2],' ', $matches[1]...` does the same thing.) – Tomalak Jul 18 '20 at 08:51