I have a few video file like this:
VideoName_s01e01.mp4
where the season and episodes are variables. I want to add an underscore ("_") between the s??
and e??
.
I have been using powershell for renaming purposes, I have a starting point:
GCI $path -filter '*_s??e??*' -rec | Ren -new { $_.name -replace '_s[0-9][0-9]', '_s[0-9]_[0-9]_' } -passthru
This actually renamed my files VideoName_s[0-9]_e[0-9].mp4
.
Basically, I am looking for the characters s??e??
I just don't know how to make them variables in the replace section.
I think the best method would be:
- Find the position of
e??s??
(let's call it X). - split the string at
X-3
. - concatenate the string with a "
_
" in the middle.
regex is the better solution, i propose other with formating number and use Template
Martin Brandl's answer provides an elegant and effective solution, but it's worth digging deeper:
PowerShell's
-replace
operator (... -replace <search>, <replace>
):takes a regular expression as its first operand,
<search>
, the search expression), and invariably matches globally (finds all matches).supports references to what the regular expression captured (and didn't capture) in the 2nd operand,
<replace>
, the replacement string (substitution string).The "replacement language" for referencing regex captures supported in
<replace>
is itself not a regular expression - no matching happens there, only references to the results of the regex matching are supported.Notably,
PowerShell does not explain the syntax of replacement strings in its
Get-Help about_comparison_operators
help topic,but the information can be found in the Substitutions in Regular Expressions .NET framework help topic, because PowerShell's
-replace
uses theRegex.Replace()
method behind the scenes.For convenience, here are the references supported in
<replace>
(excerpted from the page linked above, with emphasis and annotations added):$number
(e.g.,$1
) ... Includes the last substring matched by the capture group that is identified bynumber
, where number is a decimal value, in the replacement string.Annotations:
Including
(...)
, a parenthesized subexpression, in the regex implicitly creates a capture group (capturing group). By default, such capture groups are unnamed and must be referenced by their1
-based (decimal) index reflecting the order in which they appear in the regex, so that$1
refers to what the 1st group in your regex captured,$2
to what the 2nd captured, ...The form
${number}
(e.g.,${1}
) for disambiguation of the number is also supported (e.g., to make sure that$1
is recognized even if followed by, say,000
, use${1}000
).Instead of relying on indices to refer to unnamed capture groups, you can name capture groups and refer to them by name - see next point.
If you're not interested in what the capture group matched, you can opt to ignore it by turning it into a non-capturing group with
(?:...)
.${name}
... Includes the last substring matched by the named group that is designated by(?<name>...)
in the replacement string.$$
... Includes a single"$"
literal in the replacement string.$&
... Includes a copy of the entire match in the replacement string.$`
... Includes all the text of the input string before the match in the replacement string.$'
... Includes all the text of the input string after the match in the replacement string.$+
... Includes the last group captured in the replacement string. [This relieves you of the need to know the last group's specific index.]$_
... Includes the entire input string in the replacement string.Finally, note that:
-replace
invariably matches globally, so if the input string contains multiple matches, the replacements above apply to each match.It is generally preferable to use
'...'
(single quotes) for both the regex and the replacement string, because single-quoted strings are non-expanding (non-interpolating), and therefore avoid confusion with PowerShell's own up-front expansions of$
-prefixed tokens and interpretation of`
chars.If you do need to include a PowerShell variable, you have three options:
Use
"..."
(expanding strings) and`
-escape$
instances that are meant for the regex engine; e.g.,`$1
in the following example:'abc' -replace '(a)', "[`$1]-$HOME-"
, which yields something like[a]-C:\Users\jdoe-bc
Build your string from literal pieces and variable references using string concatenation (
+
); e.g.:'abc' -replace '(a)', ('[$1]-' + $HOME + '-')
Use
-f
, the string-formatting operator string concatenation; e.g.:'abc' -replace '(a)', ('[$1]-{0}-' -f $HOME)
Given that you need to use
$$
to escape a literal$
in the replacement string, use the following idiom to use a variable whose value you want to use literally:... -replace <search>, $var.Replace('$', '$$')
[string]::Replace()
method performing literal substring replacements.On a side note, this method is an alternative to
-replace
in simple cases, but note that it is case-sensitive by default.-replace
call, but the syntax is tricky due to the escaping requirements:... -replace <search>, ($var -replace '\$', '$$$$')
I highly recommend regex101.com for learning regex.
Something like this can work:
Gives:
-replace
is using regex, not wildcards. Thus you have to change the replace to: