我一直在尝试实现更一致的文件命名方案,并选择使用 PowerShell 来帮助完成这项任务。但是,出于某种原因,我无法让脚本用下划线替换多个模式。
$regex = [regex] '^\d{4}\d{2}\d{2}_'
# $special = [regex] '\. - '
# prepend with date
get-childitem -attributes !directory+!system | where-object {
!($_.name -match $regex)
} | rename-item -newname {
(get-date $_.creationtime -format "yyyyMMdd_") + $_.basename + $_.extension
}
# make all letters lowercase
get-childitem -attributes !directory+!system | %{
$newFilename = ($_.basename.tolower())+($_.extension.tolower());
move-item $_ $newFilename
}
# replace special chars w underscores
get-childitem -attributes !directory+!system | where-object {
$_.basename.contains(" ") -or $_.basename.contains("-") -or $_.basename.contains(" ") -or $_.basename.contains(".")
} | rename-item -newname {
$_.basename -replace "\s+-\s+", "_" -replace "-+", "_" -replace "\.+", "_" -replace "\s+", "_" + $_.extension
}
前两个块工作正常,但-replace
语句被忽略,并且没有任何东西被下划线替换。我在这里和谷歌上搜索过,但找不到有效的解决办法。
我也尝试过这种变化:
$_.basename.replace(".", "_") + $_.extension;
$_.basename.replace(" ", "_") + $_.extension
...
而不是正则表达式,但当它到达“.”部分时,文件扩展名就会混乱。它只对第一个模式有效,而忽略其余模式。
答案1
对于第三个块,你可以这样做
# replace special chars w underscores
Get-ChildItem -Attributes !directory+!system | Where-Object { $_.BaseName -match '[-+._\s]' } | ForEach-Object {
$newName = '{0}{1}' -f ($_.BaseName -replace '[-+._\s]+', '_') , $_.Extension
$_ | Rename-Item -NewName $newName -Force -WhatIf
}
-WhatIf
如果控制台输出显示正确的新文件名,则删除开关。
例子:
20190126_this is a file - name that contains + - spaces and dots.pdf
变成:
20190126_this_is_a_file_name_that_contains_spaces_and_dots.pdf
正则表达式详细信息:
[-+._\s] Match a single character present in the list below One of the characters “-+._” A whitespace character (spaces, tabs, line breaks, etc.) + Between one and unlimited times, as many times as possible, giving back as needed (greedy)
编辑
虽然上面只显示了正则表达式运算符的使用-replace
,但可以通过将原来的三个循环合并为一个来简化代码:
Get-ChildItem -Attributes !directory+!system | ForEach-Object {
# get the file's BaseName and if needed prefix the CreationTime to it
$baseName = if ($_.BaseName -notmatch '^\d{8}_') {
'{0:yyyyMMdd}_{1}' -f $_.CreationTime, $_.BaseName
}
else {
$_.BaseName
}
# do a regex -replace on the base name and combine it with the file's extension
$newName = '{0}{1}' -f ($baseName -replace '[-+._\s]+', '_') , $_.Extension
# do the rename using the lowercase $newName
$_ | Rename-Item -NewName $newName.ToLower() -Force -WhatIf
}
编辑2
灵感来自基思·米勒的注释,使用脚本块作为参数,您可以在上面的代码中-NewName
处理:ForEach-Object
Get-ChildItem -Attributes !directory+!system | Rename-Item -NewName {
# get the file's BaseName and if needed prefix the CreationTime to it
$baseName = if ($_.BaseName -notmatch '^\d{8}_') {
'{0:yyyyMMdd}_{1}' -f $_.CreationTime, $_.BaseName
}
else {
$_.BaseName
}
# do a regex -replace on the base name and combine it with the file's extension
$newName = '{0}{1}' -f ($baseName -replace '[-+._\s]+', '_') , $_.Extension
# output the new name in lower case
$newName.ToLower()
}
答案2
你可以用管道输送获取子项到foreach 对象循环获取每个文件对象及其属性值。使用正则表达式多匹配字符表达式堆叠一些替换运算符,并使用它来删除并替换基本文件名部分中不必要的字符。
本质上,这将用下划线替换点、连字符和一个或多个空格,然后在其顶部进行堆叠替换,将两个或多个连字符替换为一个连字符。
$regex = [regex] '^\d{8}_';
Get-ChildItem -attributes !directory+!system | ?{!($_.name -match $regex)} | %{
Rename-Item -path $_.FullName -newname ((get-date $_.creationtime -format "yyyyMMdd_") + $_.basename + $_.extension).ToLower()
};
Get-ChildItem -attributes !directory+!system | %{
If(($_.basename + $_.extension) -cmatch "[A-Z]"){Move-Item $_ ($_.basename + $_.extension).ToLower()}
};
Get-ChildItem -attributes !directory+!system | %{
Rename-Item -Path $_.FullName -NewName "$(Split-Path $_.FullName)\$(($_.Basename -Replace "[.]|-|\s`+","_") -Replace "_{2,}", "_")$($_.extension)"
};
支持资源
- 代替
- 获取子项
- ForEach 对象
标准别名对于 Foreach 对象:'
%
' 符号,ForEach - 重命名项目
答案3
编辑:简化代码---
$DateFilter = '^\d{8}_'
$CharFilter = '[\.\s-]+' # 'dot'or one or more whitespace or '-'
$Standarize_Name = {
$Prefix = ''
If ($_.name -notmatch $DateFilter) {
$Prefix = (get-date $_.creationtime -format "yyyyMMdd_")
}
'{0}{1}{2}' -f $Prefix,
($_.BaseName.ToLower() -replace $CharFilter, '_'),
$_.Extension
}
Get-ChildItem -Attributes !directory+!system |
Rename-Item -NewName $Standarize_Name
您的原始代码一切正常,只是需要一对括号。我拿走了您的改名ScriptBlock 并在一个简单的每一个:
PS C:\...\keith>gi 'a b - c.d.txt' | %{$_.basename -replace "\s+-\s+", "_" -replace "-+", "_" -replace "\.+", "_" -replace "\s+", "_" + $_.extension}
The -ireplace operator allows only two elements to follow it, not 3.
At line:1 char:99
+ ... \s+-\s+", "_" -replace "-+", "_" -replace "\.+", "_" -replace "\s+", ...
+ ~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Object[]:Object[]) [], RuntimeException
+ FullyQualifiedErrorId : BadReplaceArgument
最后出错了-代替因为它被读+ $_.extension
作“第三元素”。
因此解决办法是将-代替用括号括起来,然后连接$_.扩展名:
# replace special chars w underscores
get-childitem -attributes !directory+!system | where-object {
$_.basename -match '\s|-|\.')
} | rename-item -newname {
($_.basename -replace "\s+-\s+", "_" -replace "-+", "_" -replace "\.+", "_" -replace "\s+", "_") + $_.extension
}