【问题标题】:Powershell renaming with regex matched group使用正则表达式匹配组的 Powershell 重命名
【发布时间】:2018-07-30 23:57:39
【问题描述】:

我正在努力编写执行以下操作的 Powershell 命令。假设一个文件夹包含一堆随机名称与正则表达式模式匹配的文件。我想捕获与模式匹配的部分并将文件重命名为仅该部分。

例如如果模式为\w\d+\w+\d+(或类似),“asdjlk-c12aa13-.pdf”应变为“c12aa13.pdf”。

我目前的想法是这样的:

Get-ChildItem | Rename-Item -NewName { $_.Name -match $pattern ... } -WhatIf

其中... 需要替换为将代码块(即新名称)的“值”设置为匹配组的内容。 IE。我不知道如何在-match 命令之后直接访问$matched

另外,我想知道是否可以使用-match 进行惰性匹配,.*? 似乎不起作用。

【问题讨论】:

  • 对于正则表达式,您可以在一个组中捕获您想要的内容并在替换中使用这些组example
  • 正是我的想法,是的。 powershell 带来了更多的问题:/
  • 嘿...与正则表达式匹配的随机名称。我不肯定你知道随机意味着什么。 :)
  • @EBGreen 可能选词不当,当然。随机的意思是文件名中有一个随机部分不受模式控制,模式可以是任何东西,构成模式的符号可以是随机的。

标签: regex powershell


【解决方案1】:

虽然您可以遵循 -match 操作,随后通过自动 $Matches 变量提取匹配的部分,但在-replace运营商:

您只需要确保为了只返回感兴趣的部分,您必须完全匹配输入字符串,然后忽略您不关心的部分:

PS> 'asdjlk-c12aa13-.pdf' -replace '^.*?(\w\d+\w+\d+).*?(\.pdf)$', '$1$2'
c12aa13.pdf
  • ^.*?(懒惰地)匹配感兴趣部分之前的前缀。

  • (\w\d+\w+\d+) 匹配感兴趣的部分,包裹在捕获组中;由于它是正则表达式中的第一个捕获组,您可以在替换操作数中将其捕获的内容称为$1

  • .*?(懒惰地)匹配直到 .pdf 文件扩展名之后的所有内容。

  • (\.pdf)$ 与名称末尾的文件扩展名 .pdf 匹配,并且作为 2nd 捕获组,可以在替换操作数中引用为 $2

  • $1$2 简单地连接 2 个捕获组匹配项以输出所需的名称。

    • 注意:通常,对正则表达式和替换操作数都使用单引号字符串,这样$ 就不会被PowerShell意外解释提前。

    • 有关-replace 和替换操作数的语法的更多信息,请参阅我的this answer


您的命令上下文中的解决方案:

Get-ChildItem |
  Rename-Item -NewName { $_.Name -replace '^.*?(\w\d+\w+\d+).*?(\.pdf)$', '$1$2' } -WhatIf

【讨论】:

    【解决方案2】:

    更安全的方法是使用测试(类似于-WhatIf) 此示例将文件从 DSC12345 - X-1.jpg => DSC12345-X1.jpg 重命名

    # first verify what your files will convert too
    # - gets files
    # - pipes to % (foreach)
    # - creates $a variable for replacement
    # - echo replacement
    Get-ChildItem . | % { $a = $_.name -replace "^DSC(\d+)\s-\s([A-Z])-(\d).jpg$",'DSC$1-$2$3.jpg'; echo "$_.name => $a"; }
    
    # example output:
    # DSC04975-W1.jpg.name => DSC04975-W1.jpg
    # DSC04976-W2.jpg.name => DSC04976-W2.jpg
    # DSC04977-W3.jpg.name => DSC04977-W3.jpg
    # ...
    
    # use the same command and replace "echo" with "ren"
    Get-ChildItem . | % { $a = $_.name -replace "^DSC(\d+)\s-\s([A-Z])-(\d).jpg$",'DSC$1-$2$3.jpg'; ren $_.name $a; }
    

    这更安全,因为重命名在运行不正确时可能是灾难性的。

    【讨论】:

      【解决方案3】:

      说实话,我不确定你上面的那行是否可行。如果 "\w\d+\w+\d+" 是您正在寻找的模式,我会这样做:

      [regex]$regex = "\w\d+\w+\d+"    
      Get-ChildItem | ?{$_.name -match $regex} | %{rename-item $_ "$($regex.Matches($_).value).pdf"}
      

      在这种情况下,您将 Get-ChildItem 的输出传送到“foreach where 循环”(?{...}),然后将此输出传送到“foreach 循环”(%{.. .}) 重命名每个对象。

      【讨论】:

        【解决方案4】:

        您可以在脚本块中添加任意数量的内容。还隐藏 -match 的输出。正则表达式对“?”很懒惰。

        Get-ChildItem | Rename-Item -NewName { [void]($_.Name -match '.+?'); $matches.0 } -WhatIf
        
        What if: Performing the operation "Rename File" on target "Item: /Users/js/foo/afile Destination: /Users/js/foo/a".
        What if: Performing the operation "Rename File" on target "Item: /Users/js/foo/bfile Destination: /Users/js/foo/b".
        What if: Performing the operation "Rename File" on target "Item: /Users/js/foo/cfile Destination: /Users/js/foo/c".
        
        

        【讨论】:

          猜你喜欢
          • 2015-09-08
          • 2014-09-10
          • 1970-01-01
          • 2016-04-29
          • 1970-01-01
          • 2016-02-11
          • 2020-08-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多