【问题标题】:Powershell Remove Text Between before the file extension and an underscorePowershell删除文件扩展名和下划线之间的文本
【发布时间】:2019-03-18 23:13:02
【问题描述】:

我有几个 PDF 文件,它们的文件名中包含需要删除的文本。每个文件名都有几个下划线,具体取决于文件名的长度。我的目标是删除存在于.pdf 文件扩展名和最后一个_ 之间的文本。

例如我有:

  • AB_NAME_NAME_NAME_NAME_DS_123_EN_6.pdf
  • AC_NAME_NAME_NAME_DS_321_EN_10.pdf
  • AD_NAME_NAME_DS_321_EN_101.pdf

并希望将粗体部分删除成为:

  • AB_NAME_NAME_NAME_NAME_DS_123_EN.pdf
  • AC_NAME_NAME_NAME_DS_321_EN.pdf
  • AD_NAME_NAME_DS_321_EN.pdf

我是 powershell 的新手,但我做了一些研究,发现 Powershell - Rename filename by removing the last few characters 问题很有帮助,但它并不能完全满足我的需要,因为我无法硬编码要删除的字符的长度,因为它们的长度可能不同(2 -4)

Get-ChildItem 'C:\Path\here' -filter *.pdf | rename-item -NewName {$_.name.substring(0,$_.BaseName.length-3) + $_.Extension}

似乎可以使用.splitregex 来执行此操作,但我找不到解决方案。谢谢。

【问题讨论】:

  • 试试$_.BaseName.substring(0,$_.BaseName.lastindexof('_'))
  • $_.Name -replace '(_[a-z0-9]+)(?=\.pdf)'
  • @TheMadTechnician 就是这样!这说得通。来吧,把你的答案写下来,这样你就可以得到分数。我最终得到了{ $_.BaseName.substring(0,$_.BaseName.lastindexof('_')) + $_.Extension }
  • @Olaf 你的正则表达式版本去掉了.pdf 文件扩展名(除非我执行不正确?)
  • @crazymatt,它在这里按预期工作。

标签: powershell


【解决方案1】:

您可以使用[string] 类的LastIndexOf() 方法来获取字符最后一个实例的索引。在你的情况下应该这样做:

Get-ChildItem 'C:\Path\here' -filter *.pdf | rename-item -NewName { $_.BaseName.substring(0,$_.BaseName.lastindexof('_')) + $_.Extension }

【讨论】:

    【解决方案2】:

    -replace operatorregex 结合使用可实现简洁的解决方案:

    Get-ChildItem 'C:\Path\here' -Filter *.pdf | 
      Rename-Item -NewName { $_.Name -replace '_[^_]+(?=\.)' } -WhatIf
    

    -WhatIf预览重命名操作。删除它以执行实际重命名。

    • _[^_]+ 匹配 _ 字符后跟一个或多个非_ 字符 ([^-])

      • 如果您只想通过(十进制)数字更具体地匹配 (\d),请改用 _\d+
    • (?=\.) 是一个 look-ahead assertion ((?=...)),它匹配文字 . (\.),即文件扩展名的开头 不包括在匹配中.

    • 1234563扩展名。

    您还可以通过处理带有“双”扩展名的文件名使正则表达式更加健壮;例如,上述解决方案会将文件名a_bc.d_ef.pdf 替换为a.c.pdf,即执行两次 替换。为防止这种情况,请改用以下正则表达式:

    $_.Name -replace '_[^_]+(?=\.[^.]+$)'
    

    前瞻断言现在确保只有 last 扩展匹配:文字 . (\.) 后跟一个或多个 (+) 字符 其他 比字符串 ($)end 处的文字 .[^.],否定字符集 ([^...]))。

    【讨论】:

    • 虽然这符合 OP 表达的要求,但 IMO 更安全的 RE 将是 Rename-Item -NewName { $_.Name -replace '_[^_]+(?=\.pdf$)' } -WhatIfRename-Item -NewName { $_.Name -replace "_[^_]+(?=$($_.Extension)$)" } -WhatIf
    • 公平点,@LotPings,但我想保持解决方案简短。假设输入文件名仅包含 one . char - 如示例文件名中一样 - 允许我这样做。请参阅我的更新以获取一个解决方案,该解决方案还可以正确处理多个 . 实例,同时仍避免重复输入扩展。
    【解决方案3】:

    只是为了展示另一种选择,

    • 要从Name 中删除的部分是BaseName 中与_ 分开的last 元素
    • 这是来自拆分[-1]的负索引
    Get-ChildItem 'C:\Path\here' -Filter *.pdf |%{$_.BaseName.split('_\d+')[-1]} 6 10 101
    • 由于拆分删除了_,因此必须再次应用它才能将其删除。

    Get-ChildItem 'C:\Path\here' -Filter *.pdf | 
       Rename-Item -NewName { $_.Name -replace '_'+$_.BaseName.split('_')[-1] } -whatif
    

    EDIT 修改后的变体,在下划线处拆分 BaseName
    在不删除拆分字符的情况下使用 -split 运算符和
    带有zero length lookahead 的正则表达式

    > Get-ChildItem 'C:\Path\here' -Filter *.pdf |%{($_.BaseName -split'(?=_\d+)')[-1]}
    _6
    _10
    _101
    

    Get-ChildItem 'C:\Path\here' -Filter *.pdf | 
        Rename-Item -NewName { $_.Name -replace ($_.BaseName -split'(?=_)')[-1] } -whatif
    

    【讨论】:

    • 感谢您添加此内容。我一直试图让这个最初使用BaseName.split('_')[-1] 工作,但运气不佳。我也会测试这个
    • 查看最后一个更简单、更简洁的变体,因为它只删除尾随数字,因此可以重复运行而不会删除非数字部分。
    猜你喜欢
    • 2016-12-05
    • 1970-01-01
    • 2019-09-15
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 2016-04-15
    相关资源
    最近更新 更多