Cambiar el nombre de archivos reformateando los nombres de archivos existentes: marcadores de posición en cadenas de reemplazo utilizadas con el operador -replace
Tengo algunos archivos de video como este:
VideoName_s01e01.mp4
donde la temporada y los episodios son variables. Quiero agregar un guión bajo ("_") entre s??
y e??
.
he estado usandopotencia ShellPara cambiar el nombre, tengo un punto de partida:
GCI $path -filter '*_s??e??*' -rec | Ren -new { $_.name -replace '_s[0-9][0-9]', '_s[0-9]_[0-9]_' } -passthru
En realidad, esto cambió el nombre de mis archivos VideoName_s[0-9]_e[0-9].mp4
.
Básicamente, estoy buscando los caracteres, s??e??
pero no sé cómo convertirlos en variables en la sección de reemplazo.
Creo que el mejor método sería:
- Encuentra la posición de
e??s??
(llamémoslo X). - divide la cuerda en
X-3
. - concatenar la cadena con un "
_
" en el medio.
La respuesta de Martin Brandl proporciona una solución elegante y eficaz , pero vale la pena profundizar más:
-replace
Operador de PowerShell ( ... -replace <search>[, <replace>]
):
Toma una expresión regular como primer operando
<search>
(la expresión de búsqueda) e invariablemente coincide globalmente , es decir, reemplaza todas las coincidencias.'bar' -replace '[ra]', '@'
->'b@@'
- Si desea reemplazar una cadena literal , debe
\
escapar individualmente cualquier metacarácter de expresión regular (por ejemplo.
, ) o usar el resultado de una[regex]::Escape()
llamada:'bar.none' -replace '\.', '-'
->'bar-none'
'bar.none' -replace [regex]::Escape('.'), '-'
->'bar-none'
Especificar una expresión de reemplazo,
<replace>
es opcional , en cuyo caso la cadena vacía se sustituye por lo que<search>
coincide, lo que resulta en su eliminación efectiva .'bar' -replace '[ra]'
->'b'
Si
<replace>
se especifica, admite dos formas:v6.1+ ( solo PowerShell Core ): un bloque de secuencia de comandos (
{ ... }
) como operando de reemplazo, que ofrece un cálculo completamente dinámico de la cadena de reemplazo por coincidencia:'Level 41' -replace '\d+', { 1 + $_.Value }
->'Level 42'
Una cadena que contiene una expresión que puede hacer referencia a lo que la expresión regular capturó (y no capturó), como por ejemplo
$&
hacer referencia a lo que coincidió, que se explica en detalle a continuación.'bar' -replace '[ra]', '{$&}'
->'b{a}{r}'
-replace
coincide sin distinguir entre mayúsculas y minúsculas (y también se puede escribir como-ireplace
); para realizar coincidencias que distingan entre mayúsculas y minúsculas , utilice el formulario-creplace
.
<replace>
El "lenguaje de reemplazo" para hacer referencia a capturas de expresiones regulares en un operando escrito en una cadena no es en sí mismo una expresión regular ; allí no ocurre ninguna coincidencia, solo se admiten referencias a los resultados de la coincidencia de expresiones regulares , a través de $
marcadores de posición con prefijo que no deben confundirse con Variables de PowerShell .
La documentación de PowerShell (ahora) explica brevemente la sintaxis de las cadenas de reemplazo en su
about_Comparison_Operators
tema de ayuda conceptual.Para obtener una imagen completa, consulte el tema de ayuda Sustituciones en expresiones regulares de .NET Framework, que es aplicable porque PowerShell
-replace
utiliza elRegex.Replace()
método detrás de escena.
Para mayor comodidad, aquí están las referencias admitidas en la <replace>
cadena (extraídas de la página vinculada anteriormente, con énfasis y anotaciones agregadas):
$number
(por ejemplo,$1
)... Incluye la última subcadena que coincide con el grupo de captura identificado por1
-basednumber
en la cadena de reemplazo:Incluyendo
(...)
, una subexpresión entre paréntesis, en la expresión regular crea implícitamente un grupo de captura (grupo de captura). De forma predeterminada, dichos grupos de captura no tienen nombre y se debe hacer referencia a ellos mediante su índice1
basado en -decimal que refleja el orden en el que aparecen en la expresión regular , de modo que$1
se refiere a lo que capturó el primer grupo en su expresión regular,$2
a lo que capturó el segundo, ...También se admite la forma (p. ej., ) para desambiguar el número (p. ej., para asegurarse de que se reconozca incluso si va seguido de, digamos, , use ).
${number}
${1}
$1
000
${1}000
En lugar de depender de índices para hacer referencia a grupos de captura sin nombre, puede nombrar los grupos de captura y hacer referencia a ellos por su nombre; consulte el siguiente punto.
Si no está interesado en saber con qué coincidió el grupo de captura, puede optar por ignorarlo convirtiéndolo en un grupo sin captura con
(?:...)
.
${name}
... Incluye la última subcadena que coincide con el grupo de captura nombrado que está designado en la cadena de reemplazo.(?<name>...)
$$
... Incluye un único"$"
literal en la cadena de reemplazo.$&
... Incluye una copia de la coincidencia completa en la cadena de reemplazo ($0
también funciona, aunque no está documentada directamente ).$`
... Incluye el texto de la cadena de entrada antes de la coincidencia en la cadena de reemplazo.$'
... Incluye el texto de la cadena de entrada después de la coincidencia en la cadena de reemplazo.$+
... Incluye el último grupo capturado en la cadena de reemplazo. [Esto le libera de la necesidad de conocer el índice específico del último grupo.]$_
... Incluye toda la cadena de entrada en la cadena de reemplazo.
Finalmente, tenga en cuenta que:
-replace
invariablemente coincide globalmente , por lo que si la cadena de entrada contiene varias coincidencias, los reemplazos anteriores se aplican a cada coincidencia.Generalmente es preferible usar
'...'
( comillas simples ) tanto para la expresión regular como para la cadena de reemplazo, porque las cadenas entre comillas simples no se expanden (no se interpolan) y, por lo tanto, evitan la confusión con las expansiones iniciales de PowerShell de$
tokens con prefijo y interpretación de`
caracteres.
Si necesita incluir variables o expresiones de PowerShell, tiene tres opciones:Utilice
"..."
(cadenas expandibles) y`
-escape$
instancias destinadas al motor de expresiones regulares ; por ejemplo,`$1
en el siguiente ejemplo:
'abc' -replace '(a)', "[`$1]-$HOME-"
que produce algo como[a]-C:\Users\jdoe-bc
Construya su cadena a partir de piezas literales y referencias de variables usando concatenación de cadenas (
+
); p.ej:
'abc' -replace '(a)', ('[$1]-' + $HOME + '-')
Utilice
-f
, el operador de formato de cadena concatenación de cadenas; p.ej:
'abc' -replace '(a)', ('[$1]-{0}-' -f $HOME)
Dado que necesita usar
$$
para escapar un literal$
en la cadena de reemplazo , use el siguiente modismo para usar una variable cuyo valor desea usar literalmente :... -replace <search>, $var.Replace('$', '$$')
- Esto se basa en que el
[string]::Replace()
método realice reemplazos literales de subcadenas .
Como nota al margen, este método es una alternativa a-replace
los casos simples, pero tenga en cuenta que distingue entre mayúsculas y minúsculas de forma predeterminada. - Como alternativa, utilice una operación anidada
-replace
, pero la sintaxis es complicada debido a los requisitos de escape:
... -replace <search>, ($var -replace '\$', '$$$$')
Recomiendo encarecidamente regex101.com para aprender expresiones regulares.
Algo como esto puede funcionar:
"VideoName_s01e01.mp4" -replace '(.*s)(\d+)(e.*)', '$1$2_$3'
Da:
VideoName_s01_e01.mp4
-replace
esta usando expresión regular, nocomodines. Por lo tanto, debes cambiar el reemplazo a:
-replace '_s([0-9]{1,2})e([0-9]{1,2})', '_s$1_e$2_'