special - sed replace word
¿Cómo reemplazar múltiples patrones a la vez con sed? (8)
Aquí hay un
awk
basado en oogas
sed
echo ''abbc'' | awk ''{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1''
bcab
Supongamos que tengo una cadena ''abbc'' y quiero reemplazar:
- ab -> bc
- bc -> ab
Si intento dos reemplazos, el resultado no es lo que quiero:
echo ''abbc'' | sed ''s/ab/bc/g;s/bc/ab/g''
abab
Entonces, ¿qué comando sed puedo usar para reemplazar como a continuación?
echo abbc | sed SED_COMMAND
bcab
EDITAR
: En realidad, el texto podría tener más de 2 patrones y no sé cuántos reemplazos necesitaré.
Como había una respuesta que decía que
sed
es un editor de flujo y sus reemplazos son codiciosos, creo que necesitaré usar un lenguaje de script para eso.
Aquí hay una variación en la respuesta de ooga que funciona para múltiples pares de búsqueda y reemplazo sin tener que verificar cómo se pueden reutilizar los valores:
sed -i ''
s//bAB/b/________BC________/g
s//bBC/b/________CD________/g
s/________//g
'' path_to_your_files/*.txt
Aquí hay un ejemplo:
antes de:
some text AB some more text "BC" and more text.
después:
some text BC some more text "CD" and more text.
Tenga en cuenta que
/b
denota límites de palabras, que es lo que evita que
________
interfiera con la búsqueda (estoy usando GNU sed 4.2.2 en Ubuntu).
Si no está utilizando una búsqueda de límites de palabras, entonces esta técnica puede no funcionar.
También tenga en cuenta que esto da los mismos resultados que eliminar
s/________//g
y agregar
&& sed -i ''s/________//g'' path_to_your_files/*.txt
al final del comando, pero no requiere especificar el camino dos veces.
Una variación general de esto sería usar
/x0
o
_/x0_
en lugar de
________
si sabe que no aparecen
valores
nulos en sus archivos,
como sugirió jthill
.
Esto podría funcionar para usted (GNU sed):
sed -r ''1{x;s/^/:abbc:bcab/;x};G;s/^//n/;:a;//n/n/{P;d};s//n(ab|bc)(.*/n.*:(/1)([^:]*))//4/n/2/;ta;s//n(.)//1/n/;ta'' file
Esto utiliza una tabla de búsqueda que se prepara y se mantiene en el espacio de espera (HS) y luego se agrega a cada línea.
Un marcador único (en este caso
/n
) se antepone al comienzo de la línea y se utiliza como un método para avanzar en la búsqueda a lo largo de la línea.
Una vez que el marcador llega al final de la línea, el proceso finaliza y se imprime la tabla de búsqueda y los marcadores que se descartan.
NB La tabla de búsqueda se prepara desde el principio y se elige un segundo marcador único (en este caso:) para no chocar con las cadenas de sustitución.
Con algunos comentarios:
sed -r ''
# initialize hold with :abbc:bcab
1 {
x
s/^/:abbc:bcab/
x
}
G # append hold to patt (after a /n)
s/^//n/ # prepend a /n
:a
//n/n/ {
P # print patt up to first /n
d # delete patt & start next cycle
}
s//n(ab|bc)(.*/n.*:(/1)([^:]*))//4/n/2/
ta # goto a if sub occurred
s//n(.)//1/n/ # move one char past the first /n
ta # goto a if sub occurred
''
La tabla funciona así:
** ** replacement
:abbc:bcab
** ** pattern
Puede ser un enfoque más simple para la ocurrencia de un solo patrón que puede probar a continuación: echo ''abbc'' | sed ''s / ab / bc /; s / bc / ab / 2''
Mi salida:
~# echo ''abbc'' | sed ''s/ab/bc/;s/bc/ab/2''
bcab
Para múltiples ocurrencias de patrón:
sed ''s//(ab/)/(bc/)//2/1/g''
Ejemplo
~# cat try.txt
abbc abbc abbc
bcab abbc bcab
abbc abbc bcab
~# sed ''s//(ab/)/(bc/)//2/1/g'' try.txt
bcab bcab bcab
bcab bcab bcab
bcab bcab bcab
Espero que esto ayude !!
Siempre uso múltiples declaraciones con "-e"
$ sed -e ''s:AND:/n&:g'' -e ''s:GROUP BY:/n&:g'' -e ''s:UNION:/n&:g'' -e ''s:FROM:/n&:g'' file > readable.sql
Esto agregará un ''/ n'' antes de todos los AND, GROUP BY, UNION y FROM, mientras que ''&'' significa la cadena coincidente y ''/ n &'' significa que desea reemplazar la cadena coincidente con un ''/ n'' antes del ''coincidente ''
Tal vez algo como esto:
sed ''s/ab/~~/g; s/bc/ab/g; s/~~/bc/g''
Reemplace
~
con un carácter que sabe que no estará en la cadena.
Tcl tiene un builtin para esto
$ tclsh
% string map {ab bc bc ab} abbc
bcab
Esto funciona caminando la cadena de un personaje a la vez haciendo comparaciones de cadenas comenzando en la posición actual.
En perl:
perl -E ''
sub string_map {
my ($str, %map) = @_;
my $i = 0;
while ($i < length $str) {
KEYS:
for my $key (keys %map) {
if (substr($str, $i, length $key) eq $key) {
substr($str, $i, length $key) = $map{$key};
$i += length($map{$key}) - 1;
last KEYS;
}
}
$i++;
}
return $str;
}
say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
''
bcab
sed
es un editor de flujo.
Busca y reemplaza con avidez.
La única forma de hacer lo que solicitó es usar un patrón de sustitución intermedio y volver a cambiarlo al final.
echo ''abcd'' | sed -e ''s/ab/xy/;s/cd/ab/;s/xy/cd/''