在 Powershell 中使用正则表达式时 Leftpad 不起作用
Leftpad doesn't work when using with regex in Powershell
这里有两个代码块,显示了 Leftpad 的奇怪行为。
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.PadLeft(2, "0")
# output: z, fg
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.PadLeft(3, "0")
# output: 0z, 0fg
pad长度怎么不固定?
编辑:@LotPings
我问这个另一个问题是因为您在应用于 rename-item
语句时这样做的方式不会影响名称中带有括号的文件。
$file_names = ls "G:\Donwloads\Srt Downloads" -Filter *.txt
# the files are: "Data Types _ C# _ Tutorial 5.txt", "If Statements (con't) _ C# _ Tutorial 15.txt"
$file_names |
ForEach{
if ($_.basename -match '^([^_]+)_[^\d]+(\d{1,2})$')
{
$file_names |
Rename-Item -NewName `
{ ($_.BaseName -replace $matches[0], ("{0:D2}. {1}" -f [int]$matches[2],$matches[1])) + $_.Extension }
}
}
# output: 05. Data Types.txt
# If Statements (con't) _ C# _ Tutorial 15.txt
至于.PadLeft
,我以为正则表达式替换组是字符串类型的,它应该与.PadLeft
一起使用,但它没有。
你的最后一个问题应该表明你对行动顺序的假设是错误的。
又一次证明你错了。
to your 提供了一个替代方案,也适用于此:
("Data Types _ C# _ Tutorial 5", "If Statements (con't) _ C# _ Tutorial 15") |
ForEach{
if ($_ -match '^([^_]+)_[^\d]+(\d{1,2})$'){
"{0:D2}. {1}" -f [int]$matches[2],$matches[1]
}
}
示例输出:
05. Data Types
15. If Statements (con't)
您问题的最后一次编辑实际上是一个新问题...
- Rename-Item 接受管道输入,因此在使用
时不需要 ForEach-Object
Where-Object
用 -match 运算符替换 if.
$Matches 集合以相同的方式提供。
- 我真的不知道你为什么在使用 -format 运算符从头构建 NewName 时坚持使用 -replace 运算符。
$file_names = Get-ChildItem "G:\Donwloads\Srt Downloads" -Filter *.txt
$file_names | Where-Object BaseName -match '^([^_]+)_[^\d]+(\d{1,2})$' |
Rename-Item -NewName {"{0:D2}. {1}{2}" -f [int]$matches[2],$matches[1].Trim(),$_.Extension} -WhatIf
问了几天后,我正好弄明白了。
-replace
语法中的 $number
捕获组引用仅仅是文字字符串!
Powershell 从不将它们视为特殊的东西,但 Regex 引擎会。看下面的例子:
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.Length
#output: 2
# 2
看起来很奇怪?为什么 </code> 捕获组的长度都为 2,"z" 和 "fg"?答案是计算的长度是字符串 <strong><code>
而不是 "z","fg"!
我们再看一个例子,这次我们替换捕获组中的一个字母,看看会发生什么:
$array -replace "(\w{1,2})", ''.Replace("z", "6")
#output: z
# fg
输出显示 .replace
不适用于捕获组 1。
$array -replace "(\w{1,2})", ''.Replace("1", "6")
#output:
#
看到了吗?被替换的字符串是 </code> 本身。<br>
现在应该明白 <code>.padleft
问题的原因了。 PS 填充文字字符串 </code> 并用组的内容显示结果。<br>
当我用 <code>.Padleft(2, "0")
填充它时,没有任何反应,因为“$1”本身的长度为 2。
$array -replace "(\w{1,2})", ''.PadLeft(2, "0")
# output: z
# fg
如果相反,我用 .Padleft(3, "0")
填充它,这次填充方法确实生效,它将额外的“0”应用到 </code> 但显示结果前面有“0” <code>
.
的内容
$array -replace "(\w{1,2})", ''.PadLeft(3, "0")
#output: 0z
# 0fg
这里有两个代码块,显示了 Leftpad 的奇怪行为。
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.PadLeft(2, "0")
# output: z, fg
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.PadLeft(3, "0")
# output: 0z, 0fg
pad长度怎么不固定?
编辑:@LotPings
我问这个另一个问题是因为您在应用于 rename-item
语句时这样做的方式不会影响名称中带有括号的文件。
$file_names = ls "G:\Donwloads\Srt Downloads" -Filter *.txt
# the files are: "Data Types _ C# _ Tutorial 5.txt", "If Statements (con't) _ C# _ Tutorial 15.txt"
$file_names |
ForEach{
if ($_.basename -match '^([^_]+)_[^\d]+(\d{1,2})$')
{
$file_names |
Rename-Item -NewName `
{ ($_.BaseName -replace $matches[0], ("{0:D2}. {1}" -f [int]$matches[2],$matches[1])) + $_.Extension }
}
}
# output: 05. Data Types.txt
# If Statements (con't) _ C# _ Tutorial 15.txt
至于.PadLeft
,我以为正则表达式替换组是字符串类型的,它应该与.PadLeft
一起使用,但它没有。
("Data Types _ C# _ Tutorial 5", "If Statements (con't) _ C# _ Tutorial 15") |
ForEach{
if ($_ -match '^([^_]+)_[^\d]+(\d{1,2})$'){
"{0:D2}. {1}" -f [int]$matches[2],$matches[1]
}
}
示例输出:
05. Data Types
15. If Statements (con't)
您问题的最后一次编辑实际上是一个新问题...
- Rename-Item 接受管道输入,因此在使用 时不需要
Where-Object
用 -match 运算符替换 if.
$Matches 集合以相同的方式提供。- 我真的不知道你为什么在使用 -format 运算符从头构建 NewName 时坚持使用 -replace 运算符。
ForEach-Object
$file_names = Get-ChildItem "G:\Donwloads\Srt Downloads" -Filter *.txt
$file_names | Where-Object BaseName -match '^([^_]+)_[^\d]+(\d{1,2})$' |
Rename-Item -NewName {"{0:D2}. {1}{2}" -f [int]$matches[2],$matches[1].Trim(),$_.Extension} -WhatIf
问了几天后,我正好弄明白了。
-replace
语法中的 $number
捕获组引用仅仅是文字字符串!
Powershell 从不将它们视为特殊的东西,但 Regex 引擎会。看下面的例子:
$array = "z", "fg"
$array -replace "(\w{1,2})", ''.Length
#output: 2
# 2
看起来很奇怪?为什么 </code> 捕获组的长度都为 2,"z" 和 "fg"?答案是计算的长度是字符串 <strong><code>
而不是 "z","fg"!
我们再看一个例子,这次我们替换捕获组中的一个字母,看看会发生什么:
$array -replace "(\w{1,2})", ''.Replace("z", "6")
#output: z
# fg
输出显示 .replace
不适用于捕获组 1。
$array -replace "(\w{1,2})", ''.Replace("1", "6")
#output:
#
看到了吗?被替换的字符串是 </code> 本身。<br>
现在应该明白 <code>.padleft
问题的原因了。 PS 填充文字字符串 </code> 并用组的内容显示结果。<br>
当我用 <code>.Padleft(2, "0")
填充它时,没有任何反应,因为“$1”本身的长度为 2。
$array -replace "(\w{1,2})", ''.PadLeft(2, "0")
# output: z
# fg
如果相反,我用 .Padleft(3, "0")
填充它,这次填充方法确实生效,它将额外的“0”应用到 </code> 但显示结果前面有“0” <code>
.
$array -replace "(\w{1,2})", ''.PadLeft(3, "0")
#output: 0z
# 0fg