【问题标题】:remove extraneous characters from a filename从文件名中删除无关字符
【发布时间】:2017-04-02 01:18:41
【问题描述】:

我的任务有点超出我的想象,负责获取文件存储库并从文件名中删除多余的垃圾字符并将重命名的文件保存在不同的目录文件夹中。

文件名示例如下:

100-expresstoll.pdf 1000-2012-09-29.jpg 10000-2014-01-15_14.03.22.jpg 10001-2014-01-15_19.05.24.jpg 10002-2014-01-15_21.30.23.jpg 10003-2014-01-16_07.33.54.jpg 10004-2014-01-16_13.33.21.jpg 10005-2014 年 2 月 4 日.jpeg 10006-O'Reilly_Media,_Inc..pdf

开头的第一组数字是记录 ID,将与文件的扩展名一起保留。需要删除记录 ID 和文件扩展名之间的所有其他内容。

例如,前三个文件的最终名称是:

100.pdf 1000.jpg 10000.jpg

除了其他帖子,我还阅读了Removing charactersRearranging filenames,但是前面有可变字符长度的复杂性、要删除的可变数量的中间字符和可变文件扩展名类型真的把这个折腾了超出我有限的 PowerShell 范围。

【问题讨论】:

标签: powershell


【解决方案1】:

另一种没有正则表达式的方法。在以下两个示例中,都使用风险缓解参数-WhatIf 进行调试。

重命名文件:

Get-ChildItem -File | ForEach-Object {
    $oldFile = $_.FullName
    $newName = $_.BaseName.Split('-')[0] + $_.Extension
    if ($_.Name -ne $newName) {
        Rename-Item -Path $oldFile -NewName $newName -WhatIf
    }
}

重命名和移动文件:

$newDest = 'D:\test'                       ### change to fit your circumstances
Get-ChildItem -File | ForEach-Object {
    $oldFile = $_.FullName
    $newName = $_.BaseName.Split('-')[0] + $_.Extension
    $newFile = Join-Path -Path $newDest -ChildPath $newName
    if ( -not ( Test-Path -Path $newFile ) ) {
        Move-Item -Path $oldFile -Destination $newFile -WhatIf
    }
}

【讨论】:

    【解决方案2】:

    您可以使用-replace 运算符来执行这种字符串操作:

    Get-ChildItem | foreach {
    
        $old_name = $_.FullName
        $new_name = $_.Name -replace '([0-9]+).*(\.[^.]*)$', '$1$2'
    
        Rename-Item $old_name $new_name
    }
    

    正则表达式是这里的诀窍:

    1. ([0-9]+) 表示匹配一系列数字(一个或多个数字)
    2. .* 表示匹配任何东西
    3. (\.[^.]*) 表示匹配句点后跟除句点以外的任何字符
    4. $ 表示匹配必须到达字符串的末尾

    第一个和第三个的特殊之处在于它们被括号括起来,这意味着您可以在替换字符串中使用美元符号(例如$1)来使用这些值。

    【讨论】:

    • 使用$new_name = ($_.Name -replace '([0-9]+).*$', '$1') + $_.Extension 也可以在不让正则表达式找到扩展字符串的情况下工作。
    • 我非常了解 Extension 属性 - 谢谢。我的回答背后的意图是证明-replace 运算符通常可用于解决字符串操作。
    • 这不是批评。您的答案显示了使用正则表达式来获取所有内容。我的不只是另一种给猫剥皮的方法。
    • 确实 - 如果这听起来很苛刻,我深表歉意。
    【解决方案3】:

    可能最惯用的解决方法如下(假设所有感兴趣的文件 - 而没有其他文件 - 都在当前目录中。):

    Get-ChildItem -File | Rename-Item -NewName { ($_.BaseName -split '-')[0] + $_.Extension }
    

    Rename-Item 命令中添加常用参数-WhatIf,以预览重命名操作。

    请注意,Rename-Item 总是在当前位置重命名项目;要(也)移动它们,请使用Move-Item

    如果已存在同名目标,Rename-Item 会为每个此类情况报告一个非终止错误(不会中止整个处理)。
    请注意,如果输入文件名不包含 -,也可能发生这种情况,因为这会导致尝试将文件重命名为自身。

    说明:

    • Get-ChildItem -File 输出代表当前目录中文件的 [System.IO.FileInfo] 对象,这些对象通过管道 (|) 传递到 Rename-Item

    • 将脚本块 ({ ... }) 传递给 Rename-Item-NewName 参数会为每个输入对象执行包含的代码,其中 $_ 表示手头的输入对象。

      • 请注意,这种实际上未记录但经常使用的技术称为脚本块参数 [值],其中设计用于获取管道输入的参数可以与间接处理输入的脚本块绑定。
    • ($_.BaseName -split '-')[0] 从每个输入文件名的基本名称(不带扩展名的文件名)中提取第一个 - 分隔标记。

    • +,因为LHS是一个字符串,执行string连接。

    • $_.Extension 从每个输入文件名中提取文件扩展名。

    【讨论】:

      【解决方案4】:

      我知道这不是 PowerShell 的事情。如果你只是想让某些东西工作,这是一个 cmd 批处理文件。

      SETLOCAL ENABLEDELAYEDEXPANSION
      
      SET "OLDDIR=C:\Users\lit\files"
      SET "NEWDIR=C:\Users\lit\newdir"
      
      FOR /F "usebackq tokens=*" %%a IN (`DIR /A:-D /B "%OLDDIR%\*"`) DO (
          FOR /F "usebackq delims=- tokens=1" %%b IN (`ECHO %%a`) DO (SET "BN=%%b")
          SET "EXT=%%~xa"
          ECHO COPY /Y "%OLDDIR%\%%~a" "%NEWDIR%\!BN!!EXT!"
      )
      

      【讨论】:

        猜你喜欢
        • 2011-04-19
        • 2017-04-01
        • 1970-01-01
        • 2013-10-08
        • 1970-01-01
        • 2016-02-04
        • 2015-01-11
        • 1970-01-01
        相关资源
        最近更新 更多