使用 Powershell 将第二次出现的“-”替换为“_”

Posted

技术标签:

【中文标题】使用 Powershell 将第二次出现的“-”替换为“_”【英文标题】:Replacing 2nd occurrence of "-" with "_" using Powershell 【发布时间】:2019-04-19 02:34:12 【问题描述】:

我一直在使用 Powershell 来简化创建目录、重命名和移动文件的重复性任务。我正在处理文件名所需的语法非常具体的视频和 PDF 文件。到目前为止,我已经能够纠正我遇到的所有常见错误,但是这个让我很难过。

我的文件的正确语法包括:

01A-50_02A-50-CIPP-PRE.MP4
01AA-50_02AA-50-CIPP-PNSL.PDF
W01AA-48_02AA-48-CIPP-PST-CMP.MPG

我收到了大量如下所示的文件:

01A-50-02A-50-CIPP-PRE.MP4
01AA-50-02AA-50-CIPP-PNSL.PDF
W01AA-48-02AA-48-CIPP-PST-CMP.MPG

我需要用下划线替换第二个破折号,同时保持其他破折号不受影响。否则,我可以在 excel 的帮助下批量执行此操作,但我希望有一个简短的代码,可以在语法中找到并纠正此错误,而无需将列表导出到 excel,使用文本到列,然后连接字母数字部分重新组合在一起。我也不想手动更正所有这些文件名。

根据我的研究,不可能针对特定出现的字符进行替换。我最接近的想法是我找到了一个涉及 REGEX 以及识别和替换模式的解决方案。我无法对此做任何建设性的事情。

我使用此代码的方法是打开包含错误命名文件的文件夹,在其中打开一个 Powershell 窗口,从我桌面上的 txt 文件中复制代码,然后将其粘贴到 Powershell 中。

对此的任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

-replace 运算符与正则表达式一起使用:

Get-ChildItem |
  Rename-Item -NewName  $_.Name -replace '^([^_-]+-[^_-]+)-', '$1_'  -WhatIf

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

Regex '^([^_-]+-[^_-]+)-' 捕获文件名开头 (^) 的前两个 - 分隔标记,使用捕获组 ((...)) 捕获除第二个 - 之外的标记。

[^_-]+ 捕获既不是- 也不是_ 的任何非空字符运行。 _ 也被排除在外,以防止误报已经正确正确的文件名;对于那些,不排除 _ 将匹配第一个 3 标记并在那里插入 additional _

替换操作数 $1_ 然后使用第一个(也是唯一的)捕获组 ($1) 的值,后跟文字 _ 替换正则表达式匹配的内容,这实际上替换了第二个 @987654338 @ 带有_

如果给定的文件名与正则表达式不匹配(如果它已经正确),则按原样返回名称,这在 Rename-Item 的上下文中是一个安静的空操作。

【讨论】:

【参考方案2】:

看看你的例子,第二个- 似乎总是出现在数字之间。类似$Variable -replace 'REGEX','_'

使用下面的正则表达式将匹配那些。

(?<=[0-9])(.)(?=[0-9])

() 创建一个组来匹配,它是一个捕获组。

?&lt;= 是一个正向的lookbehind,它匹配主表达式之前的一个组,而不包括在结果中

[0-9] 是字符集,匹配 0 到 9 之间的任何值。

. 匹配除换行符以外的任何字符

?= 是正向前瞻,它匹配主表达式之后的组,而不包括在结果中

我建议使用Regexr 来测试和学习正则表达式。

【讨论】:

不幸的是,并非总是在数字之间。有时像这样 E21U-50A_E21U-50-CIPP-PST-CMP【参考方案3】:

您可以在- 的前两次出现处拆分字符串,然后通过-_ 连接它们:

$name = '01A-50-02A-50-CIPP-PRE.MP4'
$first,$second,$rest = $name -split '-',3
$newName = "$first-$second_$rest"

【讨论】:

出于某种原因,'0-1_2' -f $first, $second, $rest 对我来说似乎更好。 [咧嘴一笑]【参考方案4】:

这个 RegEx:(?&lt;=(^|\n)[^-]*-[^-]*)- 怎么样?

或作为完整命令(使用Replace Part of File Name Powershell 的答案):

Get-ChildItem | Rename-Item -NewName $_.name -replace '(?<=^[^-_]+-[^-_]+)-','_'

编辑:incorporated suggestions from @mklement0

【讨论】:

成功了!这就是我想要做的。【参考方案5】:

谢谢所罗门·乌科! 这几乎正​​是我想要的。

获取子项 | Rename-Item -NewName $.name -replace '(?'

它在我可以扔给它的所有示例上都非常有效,除了... 如果我在一组错误命名和正确命名的文件上运行代码,它会在它不属于的地方添加另一个下划线......

"E21U-50A_E21U_50-CIPP-PST-CMP"

而不是

"E21U-50A_E21U-50-CIPP-PST-CMP"

解决这个问题很简单。 我所做的只是首先将所有_s 替换为-s。

Get-ChildItem | Rename-Item -NewName $_.name -replace '_','-'

Get-ChildItem | Rename-Item -NewName $_.name -replace '(?<=(^|\n)[^-]*-[^-]*)-','_'

感谢所有有其他想法的人。诚然,我没有尝试过它们,因为这个解决方案是我尝试的第一个解决方案,并且成功了。 但是,我会在完成工作后修改其他解决方案。 再次感谢。

【讨论】:

以上是关于使用 Powershell 将第二次出现的“-”替换为“_”的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 移动零

将第二条记录添加到数据库后,代号为一个 Sqlite 问题

Jquery Click 事件在第二次点击时触发,但不是第一次

支付宝福卡怎么最快

高级软件工程-第二次作业-数独

c语言中如何在一个字符串中查找/出现的位置?需要第一次出现和第二次出现中间的内容和第二次出现和第三