重命名文件通过重新格式化现有的文件名 - 使用替换字符串中的占位符与-replace运算符配合使用。

3
我有一些视频文件,格式如下:VideoName_s01e01.mp4,其中季节和集数是变量。我想在s??e??之间添加下划线(“_”)。
我一直在使用 进行重命名,这是我的起点:
GCI $path -filter '*_s??e??*' -rec |  Ren -new { $_.name -replace '_s[0-9][0-9]', '_s[0-9]_[0-9]_' } -passthru    

这实际上重命名了我的文件VideoName_s[0-9]_e[0-9].mp4
基本上,我正在寻找字符s??e??,我不知道如何在替换部分中将它们变成变量。
我认为最好的方法是:
1. 找到e??s??的位置(我们称之为X)。
2. 在X-3处拆分字符串。
3. 将字符串与"_"连接起来。
4个回答

12

Martin Brandl的回答提供了一种优雅而有效的解决方案, 但值得深入挖掘:

PowerShell的-replace运算符... -replace <search>[, <replace>]):

  • 以正则表达式作为第一个操作数 <search>(搜索表达式),并始终进行全局匹配,即替换所有匹配项。

    • 'bar' -replace '[ra]', '@' -> 'b@@'
    • 如果要替换字面字符串,必须逐个对任何正则表达式元字符(例如.)进行\转义,或者使用来自[regex]::Escape()调用的结果:
      • 'bar.none' -replace '\.', '-' -> 'bar-none'
      • 'bar.none' -replace [regex]::Escape('.'), '-' -> 'bar-none'
  • 指定替换表达式 <replace> 是可选的,如果不指定,则将空字符串替换为<search>匹配的内容,从而实现其有效的删除

    • 'bar' -replace '[ra]' -> 'b'
  • 如果指定了 <replace>,它支持两种形式:

    • v6.1+(仅PowerShell Core):将一个脚本块{ ... })作为替换操作数,可以根据每个匹配动态计算替换字符串:

      • 'Level 41' -replace '\d+', { 1 + $_.Value } -> 'Level 42'
    • 包含一个表达式的字符串,该表达式可以引用正则表达式捕获的内容(以及未捕获的内容)- 例如 $& 引用了匹配的内容 - 下面详细介绍。

      • 'bar' -replace '[ra]', '{$&}' -> 'b{a}{r}'
  • -replace进行不区分大小写的匹配(也可以写成-ireplace),要执行区分大小写的匹配,请使用形式-creplace


在字符串类型的<replace>操作数中,用于引用正则表达式捕获的"替换语言"本身不是一个正则表达式 - 不会在此处进行匹配,只支持对正则表达式匹配结果的引用,通过$为前缀的占位符来实现,这与PowerShell变量不容混淆。

PowerShell的文档(现在)简要解释了替换字符串的语法,可以在其概念性帮助主题about_Comparison_Operators中找到。
要了解完整情况,请参考适用于PowerShell的-replace使用的Regex.Replace()方法的.NET框架帮助主题Substitutions in Regular Expressions
为了方便起见,以下是<replace>字符串中支持的引用(摘自上述链接页面,并添加了强调和注释):
  • $number(例如,$1)... 包括替换字符串中由基于 1number 标识的捕获组所匹配的最后一个子字符串:

    • 在正则表达式中包含 (...),即括号内的子表达式,会隐式创建一个捕获组。默认情况下,这些捕获组是无名的,并且必须通过它们在正则表达式中出现的顺序来引用,因此 $1 引用了正则表达式中第一个组捕获的内容,$2 引用了第二个组捕获的内容,依此类推。

    • 也支持形式为 ${number}(例如,${1})的写法,用于消除数字的歧义(例如,确保即使后面跟着 000$1 也能被识别,可以使用 ${1}000)。

    • 除了依赖索引来引用无名捕获组之外,您还可以给捕获组命名,并通过名称引用它们 - 请参阅下一点。

    • 如果您对捕获组匹配的内容不感兴趣,可以将其转换为非捕获组,使用 (?:...)

  • ${name} ... 包括替换字符串中由 (?<name>...) 指定的命名捕获组所匹配的最后一个子字符串。

  • $$ ... 在替换字符串中包含一个单独的"$" 字面量

  • $& ... 在替换字符串中包含整个匹配项的副本(即使没有直接文档化,$0 也可以使用)。

  • $` ... 在替换字符串中包含匹配项之前的输入字符串

  • $' ... 在替换字符串中包含匹配项之后的输入字符串

  • $+ ... 在替换字符串中包含最后一个捕获组的内容。[这样您就不需要知道最后一个组的具体索引。]

  • $_ ... 在替换字符串中包含整个输入字符串。

最后,请注意:
  • -replace 无论如何都会匹配 全局,所以如果输入字符串包含 多个 匹配项,则上述替换将应用于 每个 匹配项。

  • 通常最好使用 '...'单引号 来表示正则表达式和替换字符串,因为单引号字符串是非扩展的(非插值的),因此避免与 PowerShell 自身的前置扩展(以 $ 为前缀的标记)和对 ` 字符的解释混淆。
    如果确实需要包含 PowerShell 变量或表达式,有三种选择:

    • 使用 "..."(可扩展字符串)并使用 ` 转义 正则表达式引擎 中的 $ 实例;例如,在以下示例中使用 `$1
      'abc' -replace '(a)', "[`$1]-$HOME-"
      这将产生类似于 [a]-C:\Users\jdoe-bc 的结果。

    • 使用字符串连接(+)从文字片段和变量引用构建字符串;例如:
      'abc' -replace '(a)', ('[$1]-' + $HOME + '-')

    • 使用字符串格式化运算符 -f 进行字符串连接;例如:
      'abc' -replace '(a)', ('[$1]-{0}-' -f $HOME)

  • 考虑到您需要在 替换 字符串中使用 $$ 转义字面量的 $,请使用以下习语来使用要以 字面意义 使用其值的 变量

    • ... -replace <search>, $var.Replace('$', '$$')
    • 这依赖于 [string]::Replace() 方法 执行 字面子字符串 替换。
      顺便说一下,这种方法是在简单情况下替代 -replace 的一种选择,但请注意,默认情况下它是区分大小写的。
    • 或者,使用 嵌套的 -replace 操作,但由于转义要求,语法会有些棘手:
      ... -replace <search>, ($var -replace '\$', '$$$$')

2

我强烈推荐使用regex101.com学习正则表达式。

类似以下内容可以起到作用:

"VideoName_s01e01.mp4" -replace '(.*s)(\d+)(e.*)', '$1$2_$3'

给出:

VideoName_s01_e01.mp4

1

-replace 使用的是,而不是。因此您需要将替换更改为:

-replace '_s([0-9]{1,2})e([0-9]{1,2})', '_s$1_e$2_'

1
正则表达式是更好的解决方案,我建议使用格式化数字和模板来完成其他任务。
$exampleoffile = @"
namev1_s01e01.mp4
namvev2_s03e02.mp4
VideoName_s20e15.mp4
VideoName_s15e1.mp4
VideoName_s1e16.avi
VideoName_s1e23.mv
"@

$template=@"
{file*:{prefix:Test1}_s{season:01}e{episode:01}{extension:.mp4}}
{file*:{prefix:1xxx}_s{season:100}e{episode:5}{extension:.mp4}}
{file*:{prefix:yyy3}_s{season:10}e{episode:02}{extension:.havi}}
"@



$exampleoffile | ConvertFrom-String -TemplateContent $template | 
% { "{0}_{1:D2}_e{2:D2}{3}" -f $_.file.prefix, [int]$_.file.season, [int]$_.file.episode, $_.file.extension }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接