Tengo un texto en un archivo de texto, donde quiero que se elimine todo lo que está entre cadenas como \{{[}
y , incluidas estas cadenas. {]}\}
Estas dos cuerdaspoderse encuentran tanto en rectas diferentes como en la misma recta. En cualquier caso, enla línea en la que \{{[}
se encuentra el comienzo, no quiero que se borre el texto anterior, es decir, el izquierdo, y lo mismo se aplica al texto posterior {]}\}
.
Aquí hay un ejemplo: Dado un archivo de texto con el contenido
Bla Bla bla bla \{{[} more bla bla
even more bla bla bla bla.
A lot of stuff might be here.
Bla bla {]}\} finally done.
Nonetheless, the \{{[} show {]}\} goes on.
el script debería devolver otro archivo de texto con el contenido
Bla Bla bla bla finally done.
Nonetheless, the goes on.
Desafortunadamente, esta tarea que parecía simple resultó ser demasiado difícil para mí sed
. estoy feliz concualquiersolución en cualquier idioma, siempre y cuando no tenga que instalar nada en mi máquina Linux estándar (C y algo de Java ya están instalados).
Respuesta1
Con perl
:
perl -0777 -pe 's/\Q\{{[}\E.*?\Q{]}\}\E//gs'
Tenga en cuenta que toda la entrada se carga en la memoria antes de ser procesada.
\Qsomething\E
debe something
ser tratado como una cadena literal y no como una expresión regular.
Para modificar un archivo normal in situ, agregue la -i
opción:
perl -0777 -i -pe 's/\Q\{{[}\E.*?\Q{]}\}\E//gs' file.txt
Con GNU awk
o mawk
:
awk -v 'RS=\\\\\\{\\{\\[}|\\{\\]}\\\\}' -v ORS= NR%2
Allí estamos definiendo elseparador de registroscomo cualquiera de esos marcadores de inicio o fin (aquí solo gawk
se mawk
admite RS
una expresión regular). Pero necesitamos escapar de los caracteres que son operadores de expresiones regulares (barra invertida, {
, [
) y también de la barra invertida una vez más porque es especial en los argumentos para -v
(usado para cosas como \n
, \b
...), de ahí las numerosas barras invertidas.
Entonces todo lo que tenemos que hacer es imprimir cada dos registros. NR%2
sería 1
(verdadero) para cada registro impar.
Para ambas soluciones, asumimos que los marcadores coinciden y que esas secciones no están anidadas.
Para modificar el archivo in situ, con versiones recientes de GNU awk
, agregue la -i /usr/share/awk/inplace.awk
opción ¹.
¹no utilice-i inplace
as gawk
intenta cargar primero la inplace
extensión (como inplace
o inplace.awk
) desde el directorio de trabajo actual, donde alguien podría haber colocado malware. La ruta de la inplace
extensión suministrada gawk
puede variar según el sistema; consulte el resultado degawk 'BEGIN{print ENVIRON["AWKPATH"]}'
Respuesta2
sed -e:t -e'y/\n/ /;/\\{{\[}/!b' \
-e:N -e'/\\{{\[.*{\]}\\}/!N' \
-e's/\(\\{{\[}\).*\n/\1/;tN' \
-e'y/ /\n/;s/\\{{\[}/& /;ts' \
-e:s -e's/\(\[} [^ ]*\)\({\]}\\}\)/\1 \2/' \
-ets -e's/..... [^ ]* .....//;s/ //g;bt' \
<<""
#Bla Bla {]}\} bla bla \{{[} more bla bla
#even more bla bla bla bla. \{{[}
#
#A lot of stuff might be here.
#hashes are for stupid syntax color only
#Bla bla {]}\} finally {]}\} done.
#
#Nonetheless, the \{{[} show {]}\} goes \{{[} show {]}\} on.
#Bla Bla {]}\} bla bla finally {]}\} done.
#
#Nonetheless, the goes on.
Sin embargo, aquí hay una manera mucho mejor. Muchas menos sustituciones, y las que se realizan son para un par de personajes a la vez en lugar de .*
todo el tiempo. Prácticamente el único momento .*
que se utiliza es para limpiar el espacio del patrón del espacio intermedio cuando el primer inicio que ocurre está definitivamente emparejado con el primer final siguiente. El resto del tiempo sed
simplemente D
elimina todo lo que sea necesario para llegar al siguiente delimitador que aparece. Don me enseñó eso.
sed -etD -e:t -e'/\\{{\[}/!b' \
-e's//\n /;h;D' -e:D \
-e'/^}/{H;x;s/\n.*\n.//;}' \
-ett -e's/{\]}\\}/\n}/' \
-e'/\n/!{$!N;s//& /;}' -eD \
<<""
#Bla Bla {]}\} bla bla \{{[} more bla bla
#even more bla bla bla bla. \{{[}
#
#A lot of stuff might be here.
#hashes are for stupid syntax color only
#Bla bla {]}\} finally {]}\} done.
#
#Nonetheless, the \{{[} show {]}\} goes \{{[} show {]}\} on.
#Bla Bla {]}\} bla bla finally {]}\} done.
#
#Nonetheless, the goes on.
\n
Sin embargo, es posible que sea necesario reemplazar los escapes de línea ewline de RHS con nuevas líneas de escape con barra invertida literal.
Aquí hay una versión más genérica:
#!/usr/bin/sed -f
####replace everything between START and END
#branch to :Kil if a successful substitution
#has already occurred. this can only happen
#if pattern space has been Deleted earlier
t Kil
#set a Ret :label so we can come back here
#when we've cleared a START -> END occurrence
#and check for another if need be
:Ret
#if no START, don't
/START/!b
#sigh. there is one. get to work. replace it
#with a newline followed by an S and save
#a copy then Delete up to our S marker.
s||\
S|
h;D
#set the :Kil label. we'll come back here from now
#on until we've definitely got END at the head of
#pattern space.
:Kil
#do we?
/^E/{
#if so, we'll append it to our earlier save
#and slice out everything between the two newlines
#we've managed to insert at just the right points
H;x
s|\nS.*\nE||
}
#if we did just clear START -> END we should
#branch back to :Ret and look for another START
t Ret
#pattern space didnt start w/ END, but is there even
#one at all? if so replace it w/ a newline followed
#by an E so we'll recognize it at the next :Kil
s|END|\
E|
#if that last was successful we'll have a newline
#but if not it means we need to get the next line
#if the last line we've got unmatched pairs and are
#currently in a delete cycle anyway, but maybe we
#should print up to our START marker in that case?
/\n/!{
#i guess so. now that i'm thinking about it
#we'll swap into hold space, and Print it
${ x;P;d
}
#get next input line and add S after the delimiting
#newline because we're still in START state. Delete
#will handle everything up to our marker before we
#branch back to :Kil at the top of the script
N
s||&S|
}
#now Delete will slice everything from head of pattern space
#to the first occurring newline and loop back to top of script.
#because we've definitely made successful substitutions if we
#have a newline at all we'll test true and branch to :Kil
#to go again until we've definitely got ^E
D
...sin comentarios...
#!/usr/bin/sed -f
t Kil
:Ret
/START/!b
s||\
S|
h;D
:Kil
/^E/{
H;x
s|\nS.*\nE||
}
t Ret
s|END|\
E|
/\n/!{
${ x;P;d
}
N
s||&S|
}
D
Copié la versión comentada en mi portapapeles e hice:
{ xsel; echo; } >se.sed
chmod +x se.sed
./se.sed <se.sed
#!/usr/bin/sed -f
####replace everything between
#branch to :Kil if a successful substitution
#has already occurred. this can only happen
#if pattern space has been Deleted earlier
t Kil
#set a Ret :label so we can come back here
#when we've cleared a occurrence
#and check for another if need be
:Ret
#if no at the head of
#pattern space.
:Kil
#do we?
/^E/{
#if so, we'll append it to our earlier save
#and slice out everything between the two newlines
#we've managed to insert at just the right points
H;x
s|\nS.*\nE||
}
#if we did just clear we should
#branch back to :Ret and look for another , but is there even
#one at all? if so replace it w/ a newline followed
#by an E so we'll recognize it at the next :Kil
s|END|\
E|
#if that last was successful we'll have a newline
#but if not it means we need to get the next line
#if the last line we've got unmatched pairs and are
#currently in a delete cycle anyway, but maybe we
#should print up to our
Respuesta3
Si su archivo es test.txt puede usar:
sed ':a;N;$!ba;s/\n/ /g' test.txt|sed 's/\\{{\[}.*{\]}\\}//'
el primer sed elimina todas las nuevas líneas, el segundo elimina el texto dentro de las etiquetas.
No sé si necesitas una solución más general.