通过重新格式化现有文件名来重命名文件 - 与 -replace 运算符一起使用的替换字符串中的占位符
Posted
技术标签:
【中文标题】通过重新格式化现有文件名来重命名文件 - 与 -replace 运算符一起使用的替换字符串中的占位符【英文标题】:Renaming files by reformatting existing filenames - placeholders in replacement strings used with the -replace operator 【发布时间】:2017-04-02 15:12:03 【问题描述】:我有一些这样的视频文件:
VideoName_s01e01.mp4
季节和剧集是可变的。我想在s??
和e??
之间添加一个下划线(“_”)。
我一直使用powershell 进行重命名,我有一个起点:
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??
我只是不知道如何在替换部分中使它们成为变量。
我认为最好的方法是:
-
找到
e??s??
的位置(我们称之为X)。
在X-3
处拆分字符串。
将字符串与中间的“_
”连接起来。
【问题讨论】:
【参考方案1】:-replace
使用的是regex,而不是wildcards。因此,您必须将替换更改为:
-replace '_s([0-9]1,2)e([0-9]1,2)', '_s$1_e$2_'
【讨论】:
【参考方案2】:我强烈推荐 regex101.com 来学习正则表达式。
这样的东西可以工作:
"VideoName_s01e01.mp4" -replace '(.*s)(\d+)(e.*)', '$1$2_$3'
给予:
VideoName_s01_e01.mp4
【讨论】:
【参考方案3】:Martin Brandl's answer provides an elegant and effective solution,但值得深入挖掘:
PowerShell 的 -replace
运算符 (... -replace <search>[, <replace>]
):
将regular expression 作为其第一个操作数<search>
(搜索表达式),并且总是全局匹配,即替换所有匹配。 p>
'bar' -replace '[ra]', '@'
-> 'b@@'
指定替换表达式<replace>
是可选,在这种情况下空字符串 替换<search>
匹配的内容,从而使其有效删除。
'bar' -replace '[ra]'
-> 'b'
如果指定<replace>
,则支持两种形式:
v6.1+(仅限 PowerShell Core):一个 脚本块 ( ...
) 作为替换操作数,它提供了完全在每个匹配的基础上动态计算替换字符串 - 有关示例,请参见 this answer。
'bar' -replace '[ra]', '' + $_.Value + ''
-> 'bar'
一个 string 包含一个表达式,该表达式可以引用正则表达式捕获(和未捕获)的内容 - 例如 $&
来引用匹配的内容 - 下面将详细解释。
'bar' -replace '[ra]', '$&'
-> 'bar'
-replace
匹配大小写-不敏感(也可以写成-ireplace
);要执行区分大小写的匹配,请使用-creplace
形式。
在字符串类型的<replace>
操作数中引用正则表达式捕获的“替换语言”本身不是正则表达式 - 没有匹配发生,仅支持对正则表达式匹配的结果的引用,通过$
-前缀占位符不要与混淆PowerShell 变量。
PowerShell 的文档(现在)在其概念性about_Comparison_Operators
帮助主题中简要解释了替换字符串的语法。
完整图片参考Substitutions in Regular Expressions.NET框架帮助主题,因为PowerShell的-replace
使用Regex.Replace()
方法
在幕后。
为方便起见,以下是<replace>
字符串中支持的引用(摘自上面链接的页面,并添加了重点和注释):
$<em>number</em>
(eg, $1
) ... 包括替换字符串中由基于1
的<em>number</em>
标识的捕获组匹配的最后一个子字符串:
包括(...)
,一个带括号的子表达式,在正则表达式中隐式创建一个捕获组(捕获组)。默认情况下,此类捕获组未命名,并且必须由它们的 1
-based(十进制)index 引用,反映它们在正则表达式中出现的顺序,所以$1
指的是你的正则表达式中的第一组捕获的内容,$2
指的是第二组捕获的内容,...
还支持用于数字消歧的$<em>number</em>
(例如$1
)形式(例如,确保$1
即使后面跟着@ 987654365@,使用$1000
)。
您可以命名捕获组并按名称引用它们,而不是依赖 indices 来引用未命名的捕获组 - 请参阅下一点。
如果您对捕获组匹配的内容不感兴趣,您可以选择忽略它,通过 (?:...)
将其转换为非捕获组。
$<em>name</em>
... 包括替换字符串中由(?<<em>name</em>>...)
指定的命名捕获组匹配的最后一个子字符串。
$$
... 在替换字符串中包含一个 "$"
文字。
$&
... 在替换字符串中包含整个匹配项的副本($0
也可以,尽管它是isn't directly documented)。
$`
... 在替换字符串中包含输入字符串匹配之前的文本。
$'
... 在替换字符串中包含输入字符串匹配后的文本。
$+
... 在替换字符串中包含最后组捕获。 [这使您无需知道最后一组的具体索引。]
$_
... 在替换字符串中包含整个输入字符串。
最后,请注意:
-replace
始终匹配全局,因此如果输入字符串包含多个匹配,则上述替换适用于每个 匹配。
通常最好对正则表达式和替换字符串使用'...'
(单引号),因为单引号字符串是非扩展的(非-interpolating),因此避免与 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()
method 执行文字子字符串替换。
附带说明一下,在简单情况下,此方法是 -replace
的替代方法,但请注意,默认情况下它是区分大小写的。
或者,使用 嵌套 -replace
操作,但由于转义要求,语法很棘手:... -replace <search>, ($var -replace '\$', '$$$$')
【讨论】:
【参考方案4】:regex 是更好的解决方案,我建议使用其他格式化数字并使用模板
$exampleoffile = @"
namev1_s01e01.mp4
namvev2_s03e02.mp4
VideoName_s20e15.mp4
VideoName_s15e1.mp4
VideoName_s1e16.avi
VideoName_s1e23.mv
"@
$template=@"
file*:prefix:Test1_sseason:01eepisode:01extension:.mp4
file*:prefix:1xxx_sseason:100eepisode:5extension:.mp4
file*:prefix:yyy3_sseason:10eepisode:02extension:.havi
"@
$exampleoffile | ConvertFrom-String -TemplateContent $template |
% "0_1:D2_e2:D23" -f $_.file.prefix, [int]$_.file.season, [int]$_.file.episode, $_.file.extension
【讨论】:
以上是关于通过重新格式化现有文件名来重命名文件 - 与 -replace 运算符一起使用的替换字符串中的占位符的主要内容,如果未能解决你的问题,请参考以下文章
通过使用 nmake 文件附加系统时间来重命名 .exe 文件
如何通过在 Windows 中使用批处理替换子字符串来重命名文件 [关闭]