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

Renaming files by reformatting existing filenames - placeholders in replacement strings used with the -replace operator

提问人:IHaveSumQuestions 提问时间:11/19/2016 最后编辑:mklement0IHaveSumQuestions 更新时间:8/26/2023 访问量:3041

问:

我有一些这样的视频文件:其中季节和剧集是变量。我想在 和 之间添加一个下划线 (“_”)。VideoName_s01e01.mp4s??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. 找到的位置(我们称之为 X)。e??s??
  2. 在 处拆分字符串。X-3
  3. 将字符串与中间的“”连接起来。_
PowerShell 文件 替换 重命名 正则表达式 通配符

评论


答:

1赞 Martin Brandl 11/19/2016 #1

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

-replace '_s([0-9]{1,2})e([0-9]{1,2})', '_s$1_e$2_'
2赞 Kory Gill 11/19/2016 #2

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

像这样的东西可以工作:

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

给:

VideoName_s01_e01.mp4
12赞 mklement0 11/19/2016 #3

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'
  • 指定替换表达式 是可选的,在这种情况下,空字符串将替换为 whats,从而有效删除该表达式。<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帮助主题中简要介绍了替换字符串的语法。

  • 有关完整情况,请参阅正则表达式 .NET Framework 中的替换帮助主题,该主题适用,因为 PowerShell 使用 Regex.Replace() 方法 幕后花絮。-replace

为方便起见,以下是<replace>字符串中支持的引用(摘自上面链接的页面,并添加了强调和注释):

  • $number(例如,)......包括由替换字符串1 开始的数字标识的捕获组匹配的最后一个子字符串$1

    • 包括括号内的子表达式,在正则表达式中隐式创建一个捕获组(capturing group)。默认情况下,此类捕获组是未命名的,并且必须由其基于 1 的(十进制)索引引用,以反映它们在正则表达式中的出现顺序,因此它指的是正则表达式中的第一个组捕获的内容,第二个捕获的内容,...(...)$1$2

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

    • 您可以命名捕获组并按名称引用它们,而不是依赖索引来引用未命名捕获组 - 请参阅下一点。

    • 如果您对捕获组匹配的内容不感兴趣,可以选择忽略它,方法是将其转换为带有 的非捕获组。(?:...)

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

  • $$...在替换字符串中包含单个“$”文本

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

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

  • $'...在替换字符串中包括匹配项后的输入字符串的文本。

  • $+...包括替换字符串中捕获的最后一个。[这样您就无需知道最后一组的特定索引。

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

最后,请注意:

  • -replace 总是全局匹配,因此如果输入字符串包含多个匹配项,则上述替换项适用于每个匹配项。

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

    • 使用用于正则表达式引擎的(可扩展字符串)和 -escape 实例;例如,在以下示例中:

      它产生类似
      "..."`$`$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 '\$', '$$$$')
1赞 Esperento57 11/19/2016 #4

正则表达式是更好的解决方案,我建议其他格式化编号并使用模板

$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 }