Reemplazar string que se repite en un txt con una cadena diferente cada uno
Gusto en saludarlo.
Soy muy amateur en este tema y he ido incursionando en el tema realizando scripts batch, para automatizar tareas en mi trabajo, con los que me ha ido bastante bien, casi siempre tomando otros como modelo y adaptándolos, alguno de esos suyos, así que agradecido por el conocimiento que Ud. Comparte.
En esta oportunidad me propuse lo siguiente y no sé bien cómo hacerlo:
Tengo un archivo donde se repite la palabra "Es copia" en distintas filas, y puede estar 4 u 8 veces. En caso de que esté 4 veces necesito cambiar las dos primeras por la palabra "Original" y las dos segundas por "duplicado". Y en el caso de que esté 8 veces, las 4 primeras por "Original" y las 4 segundas por "Duplicado".
Seguramente es sencillo pero necesitaría una ayuda para empezar.
1 respuesta
Pues he estado pensando en ello y no me parece sencillo. No se me ocurre otra forma que ir explorando la totalidad de cada línea en la que esté esa cadena (para ello puede usarse el comando FIND o el FINDSTR) en búsqueda de la cadena "Es copia" usando una especie de puntero, para contar el número de veces porque, hasta donde yo sé, esos comandos no permiten contar en una línea. Una vez hecho eso creo que ya sería más fácil aplicar uno u otro tratamiento.
De todas formas lo intentaré en la medida en que tenga tiempo libre y ya le contaré lo que vaya averiguando.
Buenas tardes ggirald.
Una aclaración: en los casos en que la cadena "Es copia" aparece, lo hace sólo una vez por fila, en el token 1, en 4 u 8 filas de todo el txt,. Creo que eso no lo expliqué con suficiente claridad.
Saludos y muchas gracias por su pronta respuesta.
Eso ya es otra cosa. Pruebe con esto:
@echo off Setlocal EnableDelayedExpansion del /q kkk.txt set cadena=Es copia set sust1=Original set sust2=Duplicado set /a contador=0 set nomarch=edugomez.txt for /f "tokens=3" %%a in ('find /c "%cadena%" %nomarch%') do set /a caso=%%a/2 for /f "tokens=*" %%a in (%nomarch%) do ( set lin=%%a echo %%a ^^| find "%cadena%">nul if not errorlevel 1 set /a contador+=1 if !contador! leq !caso! set lin=!lin:%cadena%=%sust1%! if !contador! gtr !caso! set lin=!lin:%cadena%=%sust2%! Echo ! Lin!>>kkk.txt )
Donde he puesto EDUGOMEZ.TXT debería poner el nombre del archivo que se quiere modificar. El archivo modificado se deja en KKK.TXT
Según la costumbre habitual del editor de la página, ha dejado indebidamente un espacio en el comando "echo" entre la primera admiración ("!") y el nombre de la variable, además de ponerlo con mayúsculas tanto el "echo" como "lin"
Buenas tardes ggirald, creo que tuve un error con mi última consulta y la puse como respuesta. La transcribo nuevamente:
Gracias por su respuesta y el tiempo que me dedica.
Probé el script con un txt de este estilo:
Algo Es copia Algo Es copia Algo Es copia Algo Es copia
y funciona perfecto, ya sea que aparezca 4 u 8 veces la cadena.
Cuando hice la prueba con el tipo de archivo con el que tengo que trabajar, similar al siguiente:
~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~>
Por un lado me arroja el siguiente mensaje:
y como resultado obtengo lo siguiente:
~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Original Es copia=Original ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Original Es copia=Original ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Duplicado Es copia=Duplicado ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Duplicado ~] ~>
También necesitaría conservar las filas en blanco.
He probado con el archivo que me pone como ejemplo y me ocurre algo parecido, pero no exactamente igual. Esto es lo que he hecho y lo que sale:
G:\Varios>type edugomez.txt ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Es copia ~] ~> G:\Varios>type edugomez1.bat @echo off Setlocal EnableDelayedExpansion del /q kkk.txt set cadena=Es copia set sust1=Original set sust2=Duplicado set /a contador=0 set nomarch=edugomez.txt for /f "tokens=3" %%a in ('find /c "%cadena%" %nomarch%') do set /a caso=%%a/2 for /f "tokens=*" %%a in (%nomarch%) do ( set lin=%%a echo %%a ^^| find "%cadena%">nul if not errorlevel 1 set /a contador+=1 if !contador! leq !caso! set lin=!lin:%cadena%=%sust1%! if !contador! gtr !caso! set lin=!lin:%cadena%=%sust2%! Echo ! Lin!>>kkk.txt ) G:\Varios>edugomez1 "15.1" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable. "15.1" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable. "15.1" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable. "15.1" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable. G:\Varios>type kkk.txt ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Original ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Original ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Duplicado ~] ~> ~[8 50 9 9 9 9 M. ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 @4 Duplicado ~] ~> G:\Varios>
El problema del mensaje ""15.1" no se reconoce como un comando interno o externo,
programa o archivo por lotes ejecutable." Tiene que ver con la poca "transparencia" del comando ECHO. He probado a teclear directamente el comando en una ventana CMD y sale lo mismo:
G:\Varios>echo ~#| 15.1 drlr0|M35.35 Jc Jv50 @3 "15.1" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable.
Pero aparentemente no afecta al resultado. De modo que lo que no entiendo es lo que le sale de:
@4 Original Es copia=Original
Y lo de respetar las líneas en blanco también complica un poco el asunto. Pero ya otras veces he tenido que resolver ese problema y creo que esta versión podría hacerlo:
@echo off Setlocal EnableDelayedExpansion del /q kkk.txt del /q kkkk.txt echo.> kkkk.txt set cadena=Es copia set sust1=Original set sust2=Duplicado set /a contador=0 set nomarch=edugomez.txt for /f "tokens=3" %%a in ('find /c "%cadena%" %nomarch%') do set /a caso=%%a/2 for /f "skip=2 tokens=1*" %%a in ('fc /LB1000 /n kkkk.txt %nomarch% ^| findstr -v "*****"') do ( if "%%b" == "" echo.>>kkk.txt if not "%%b" == "" ( set lin=%%b echo %%b ^^| find "%cadena%">nul if not errorlevel 1 set /a contador+=1 if !contador! leq !caso! set lin=!lin:%cadena%=%sust1%! if !contador! gtr !caso! set lin=!lin:%cadena%=%sust2%! Echo ! Lin!>>kkk.txt ) )
Si esto funciona habría que aclarar el problema de las líneas tipo:
Es copia=Original
Buenos días gggirald,
Estuve realizando pruebas con los archivos completos con los que tengo que trabajar, que son de entre 1000 y 3000 filas, y funcionó perfecto, por lo que no focalicé en el error de las lineas tipo "Es copia=Original"; seguramente ello se debió a un error de mi parte al hacer el primer test.
La única modificación que hice es "LB3500" en lugar de "LB1000", para cubrir todo el archivo.
Sólo una consulta más: el error de tipo...
no se reconoce como un comando interno o externo
...en casi la totalidad de las filas ¿es lo que puede ralentizar la ejecución del script? (para el archivo de 3000 filas toma cerca de 90 segundos)
Gracias! Saludos!
Pensaba haberle comentado lo de la posible necesidad de modificar el LB dependiendo del tamaño del archivo a tratar, pero luego pensé que 1000 ya eran bastantes y que, en todo caso, si hubiera problemas ya lo comentaríamos. Yo creo que la ralentización puede tener más que ver con ese tratamiento adicional para detectar líneas en blanco. Puede probar con la versión anterior y con esta y comparar los tiempos.
Probé las dos versiones y la diferencia es mínima: 1 segundo. Seguro el tiempo que lleva es por el gran tamaño del archivo.
Muchas gracias! Esto agiliza muchísimo mi trabajo!
Saludos cordiales desde Bahía Blanca, Argentina.
He seguido investigando un poco el asunto del "no se reconoce..." y he visto que la causa es la presencia de la "pipa" (carácter "|") en la línea correspondiente. Claramente tiene que ver con el hecho de que en MSDOS se utiliza ese carácter para "canalizar" la salida de un comando para que la trate otro comando. Eso explica que espere que lo que viene después sea un comando o un ejecutable. Hemos tenido suerte de que el problema se da en el primer ECHO interno, el que uso para buscar la cadena, y no en el segundo, el que uso para escribir en el archivo de salida. Si hubiera dado el mismo problema en ese segundo ECHO no habría funcionado el bat. Pero esto quiere decir que si se puede dar en el archivo de entrada una línea que tenga una "pipa" y la cadena "Es copia" esa línea sería contabilizada por el primer FOR pero seguramente no sería tratada en el segundo FOR.
- Compartir respuesta