Answered regex replace

  • Tuesday, January 31, 2012 8:52 PM
     
      Has Code

    Hi I'm trying to rename a bunch of file with rename-item.  I want to use a regex in conjuction w/ replace but am having some trouble.

    files are named:

    20110101_2123_8853_NIRNRGB.e1f,

    20110223_2556_1482_RGBNRGB.e1f

    and i want to rename them

    20110101_2123_NIR.e1f,

    20110223_2556_RGB.e1f

     

    get-childitem | where-object {$_.name -match "\d{1,4}_[nr][ig][rb]NRGB"}|
    foreach {Rename-Item -WhatIf $_.name $_.name.replace("\d{1,4}_NIRNRGB","_NIR")} 
    

    when I delet the

    \d{1,4}

    component of the replace parameters it seem to work.. so that tells me that my regex is wrong or not escaped properly.  Any insight?

All Replies

  • Tuesday, January 31, 2012 9:07 PM
    Moderator
     
     

    I think you have the Powershell -replace operator confused with the string .replace() method.

    The -replace operator uses regex matches.  The string method only takes literal text arguments.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
  • Tuesday, January 31, 2012 11:13 PM
     
     
    I shall contemplate this.. on the tree of woe.

     
  • Tuesday, January 31, 2012 11:22 PM
    Moderator
     
     Answered
    foreach {Rename-Item $_  -newname  ($_.name -replace "\d{1,4}_NIRNRGB","_NIR")}

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
    • Marked As Answer by Chewie Mascara Wednesday, February 01, 2012 1:20 AM
    •  
  • Tuesday, January 31, 2012 11:31 PM
     
     
    Thanks.. you were correct.  I was mixed up.   Probably still am a bit...

    Now can the -replace operator conquer multiple matches?  i.e. something like this:

      {Rename-Item $_  -newname  ($_.name -replace "\d{1,4}_NIRNRGB","_NIR", "\d{1,4}_RGBNRGB", "_RGB")?  I think i'll give it a try
  • Tuesday, January 31, 2012 11:57 PM
    Moderator
     
      Has Code

    It can, but not like that.

    '20110101_2123_8853_NIRNRGB.e1f','20110223_2556_1482_RGBNRGB.e1f'|
    foreach {$_ -replace '\d{1,4}_(NIR|RGB)NRGB','$1'}
    
    20110101_2123_NIR.e1f
    20110223_2556_RGB.e1f
    

     


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
  • Wednesday, February 01, 2012 12:41 AM
     
     
    As an aside, it occurs to me that someone doing this kind of mass renaming will find that powershell makes it easier to avoid a problem common to batch and vbscript, in which already renamed files appear again in the list of files to be renamed.
  • Wednesday, February 01, 2012 1:33 AM
     
     

    Thanks for the help.   Without taking up too much of your time could you offer some insight into the use of the $1?

     

    Again.. thanks for the help.

     

     

  • Wednesday, February 01, 2012 2:14 AM
    Moderator
     
     

    If the regex matches, the match group contents are available as $n (one for each match group, similar to $matches).  $0 will be the entire match string.  $1 will be the first captured group, etc.  In this case there is only one captured group -(NIR|RGB) - the pipe makes it an alternating match (it will match either NIR or RGB), and whichever one it was will be in $1. 

     Note that these are NOT Powershell variables - they are created by the regex,  and they must be single quoted if you use them in the replacement text argument so that Powershell does not try to evaluate the as Powershell variables.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
  • Wednesday, February 01, 2012 3:42 AM
     
     

    Excellent bit of info.  Thank you.

  • Saturday, February 18, 2012 2:26 PM
     
     

    If the regex matches, the match group contents are available as $n (one for each match group, similar to $matches).  $0 will be the entire match string.  $1 will be the first captured group, etc.  In this case there is only one captured group -(NIR|RGB) - the pipe makes it an alternating match (it will match either NIR or RGB), and whichever one it was will be in $1. 

     Note that these are NOT Powershell variables - they are created by the regex,  and they must be single quoted if you use them in the replacement text argument so that Powershell does not try to evaluate the as Powershell variables.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
    Hey here's a question:  

    Why is the first captured group ($1) the -(NIR|RGB)- portion of the regex and not the -\d{1,4}- portion?
  • Saturday, February 18, 2012 2:37 PM
    Moderator
     
     Answered

    Capture groups are defined by the parens.  In this example, \d{1,4} is not enclosed in any grouping parens, so it will not be one of the captured groups. 

    $0 will always be captured, and will always be the entire match - you can't control that.   After that, the captured groups will be up to you.  Whatever portions of the regex you enclose in parens will become the capture groups from 1 to however many groups you define in the regex.  If you want the \d{1,4} to be captured, then use:

    foreach {$_ -replace '(\d{1,4})_(NIR|RGB)NRGB','$1'}

    and it will become capture group1, and then (NIR|RGB) will become capture group 2.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    • Marked As Answer by Chewie Mascara Saturday, February 18, 2012 3:39 PM
    •  
  • Saturday, February 18, 2012 2:39 PM
     
     Answered

    Here is the Regex:

     '\d{1,4}_(NIR|RGB)NRGB'

    There is only one captured group, enclosed in ( ). That's why.  If you wanted to capture the part you mention, it will become the first captured group, and the second one will be (NIR|RGB)  :

     '(\d{1,4})_(NIR|RGB)NRGB'


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    • Marked As Answer by Chewie Mascara Saturday, February 18, 2012 3:36 PM
    •  
  • Saturday, February 18, 2012 2:44 PM
    Moderator
     
     
    Mornin Teddy :-). OT - if you don't add the new V3 OGV -passthru and -output mode parameters to your Wiki pretty soon, I'm going to.  They're too good to keep a secret  ;-). 

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

  • Saturday, February 18, 2012 3:38 PM
     
     

    Here is the Regex:

     '\d{1,4}_(NIR|RGB)NRGB'

    There is only one captured group, enclosed in ( ). That's why.  If you wanted to capture the part you mention, it will become the first captured group, and the second one will be (NIR|RGB)  :

     '(\d{1,4})_(NIR|RGB)NRGB'


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Thank you kindly for the explanation.  I do appreciate the help.

  • Saturday, February 18, 2012 3:39 PM
     
     

    Capture groups are defined by the parens.  In this example, \d{1,4} is not enclosed in any grouping parens, so it will not be one of the captured groups. 

    $0 will always be captured, and will always be the entire match - you can't control that.   After that, the captured groups will be up to you.  Whatever portions of the regex you enclose in parens will become the capture groups from 1 to however many groups you define in the regex.  If you want the \d{1,4} to be captured, then use:

    foreach {$_ -replace '(\d{1,4})_(NIR|RGB)NRGB','$1'}

    and it will become capture group1, and then (NIR|RGB) will become capture group 2.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Again, thank you.

  • Sunday, February 19, 2012 2:14 PM
     
     
    Mornin Teddy :-). OT - if you don't add the new V3 OGV -passthru and -output mode parameters to your Wiki pretty soon, I'm going to.  They're too good to keep a secret  ;-). 

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    I can't find good info on these parameters.  Perhaps you have experimented with them?  I messed about with -Passthru a bit, but it didn't behave as I expected.


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)


  • Sunday, February 19, 2012 2:45 PM
    Moderator
     
     

    The documentation isn't very good.  From what I've been able to figure out, the -passthru, -wait, and -outputmode parameters are new.

    OGV -wait runs OGV and then stops execution until you close the gridview.

    -outputmode and -passthru lets you use OGV in the middle of the pipeline as basically a prompted filter. 

    Pipe a collection to OGV -outputmode single, and it will stop the pipeline, display that collection and let you select one object from the gridview that will continue on down the pipeline when you hit the OK button at the bottom

    Use the -outputmode multi option and you can select multiple objects from the gridview to send on down the pipeline, using the normal control and shift convention for selecting multiple entries from a list.

    The -passthru switch seems to act just like -outputmode single.  I haven't figured out what the difference is there yet.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


  • Sunday, February 19, 2012 3:53 PM
     
      Has Code

    I like that -outputmode thing.  It can, for example, allow you to view all processes, and then drill down to one for more detail:

    ps | Out-GridView -OutputMode Single | ps | fl *
    


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

  • Sunday, February 19, 2012 4:05 PM
    Moderator
     
     

    I used both the single and multi options in this add-on I wrote for creating a snippet for splatting cmdlet parameters:

    http://mjolinor.wordpress.com/2012/01/16/ps-v3-ise-add-on-for-splatting-updated/

    It uses the single option to select the parameter set you want to use, then multi to select the parameters from that set that you want to splat.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

  • Sunday, February 19, 2012 4:20 PM
     
     
  • Sunday, February 19, 2012 4:26 PM
    Moderator
     
     

    Very good. 

    I thought it should be added, but also thought it better if the entries all have the same "style", and you get that when the same person is doing the maintenance.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "