6

I'm having quite a bit of trouble making a rename-script in PowerShell. The situation: In a directory I have folders named with the following format: "four digits - text - junk" Which I want to rename to "text (four digits)"

Right now I have created a directory with some sample names to play around with:

1996 - something interesting - something crappy

2006 - copy this - ignore

I've tried setting up a script to echo their names to begin with but I can't quite get the hang of the regex. The following code just prints "1996 - something" and "2006 - copy"

Get-ChildItem | Foreach-Object { if ($_.BaseName -match "(\d{4} - \w+ -*)") { echo $matches[0]}}

and this one will print "1996 - something interesting - something crappy \n ()" and "2006 - copy this - ignore\n ()"

Get-ChildItem | Foreach-Object { echo ($_.BaseName -replace "(\d{4} - \w+ - *)"), "$2 ($1)"}

Can someone tell me why neither approach respects the literal string " - " as a boundary for the matching?

*EDIT* Thanks zespri, the code that solved my problem is

Get-ChildItem | Foreach-Object {
if ($_.BaseName -match "(\d{4} - [^-]*)") { 
  Rename-Item $_ ($_.BaseName -replace "(\d{4}) - (.+)(?= -).*" ,'$2 ($1)')
  }
}

2 Answers 2

6

Will this work for you:

Get-ChildItem | Foreach-Object { 
  if ($_.BaseName -match "(\d{4} - [^-]*)") { 
      echo $matches[0].TrimEnd()
    }
}

Note the TrimEnd - this is to trim the trailing space before the second dash.

As for why your examples do not work: \w+ matches any word character so it will not match the space inside "something interesting". * means zero or more. So -* matches zero or more dashes, in your case - zero.

Another way to write an expression that might work for you is:

Get-ChildItem | Foreach-Object { 
  if ($_.BaseName -match "(\d{4} - .+(?= -))") { 
      echo $matches[0]
    }
}

where the (?= -) construct is positive lookahead assertion In this case you do not need to trim the extra space at the end as it is accounted for in the regular expression itself.

Update 1

Modified to do the transformation:

gci | %{ $_.BaseName -replace "(\d{4}) - (.+)(?= -).*" ,'$2 ($1)' }
Sign up to request clarification or add additional context in comments.

3 Comments

It will echo the names of the ones that match yes, that's a step in the right direction. Now to do something with it: Reformat to "something interesting (digits)". I've tried wrapping the two parts I want to extract in parentheses and extracting them via $matches[0].Groups[] á la stackoverflow.com/questions/614651/… but that isn't a valid operator. I've also tried doing named and unnamed groups out of them but I can't get anything other than the entire text, or an empty pair of parentheses followed by the junk.
@Glader: I was kind of hoping that a gentle nudge in the right direction would be enough =). I have modified the answer to add the code that reformats the names.
So had I but I couldn't for the life of me figure out the proper method.. tried by adding multiple or'ed char demands etc. on the first regex but there's always something biting me in the ass. ^^ Thank you so much, I've updated my original post with the code I went with.
1

Try this:

Get-ChildItem | 
    Select-String -Pattern '(\d{4})\s+-\s+(\w+(\s+\w+)*)\s+-.*' |
    Foreach-Object { "$($_.Matches.Groups[2].Value) ($($_.Matches.Groups[1].Value))" }

1 Comment

Missing closing } tag

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.