
Soy nuevo en expresiones regulares y sed, y estoy tratando de crear lo que pensé que sería una expresión regular sencilla: quiero eliminar la letra final de palabra si es una 'o'.
- Cadena de entrada: Hola Hola
- Resultado esperado: Infierno Infierno
La buena noticia: puedo eliminar la 'o' cuando está al final de la cadena:
$ echo 'Hello Hello' |sed 's/\(.*\)o/\1/g'
Hello Hell
$ echo 'Hello Hello' |sed 's/\(.*\)o$/\1/g'
Hello Hell
La mala noticia: no puedo eliminarlo de las palabras anteriores en la cadena. He probado esto con todos los símbolos de anclaje que se me ocurren. El resultado es que no se elimina ninguna de las 'o' finales de palabra:
$ echo 'Hello Hello' |sed 's/\(.*\)o\b/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\>/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\W/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\s/\1/g'
Hello Hello
¿Podrías ayudarme a recuperar la cordura diciéndome qué estoy haciendo mal?
Actualización: tengo la impresión clara de que mi máquina produce resultados diferentes a los de otras personas. Estoy usando la ventana de terminal en mi Macbook. Si alguien puede arrojar algo de luz sobre esto, por favor dímelo.
Respuesta1
echo 'Hello Hello' | sed 's/o$//'
Me parece más útil que tu.
echo 'Hello Hello' | sed 's/\(.*\)o$/\1/g'
En su pregunta se dice que la salida de
echo 'Hello Hello' | sed 's/\(.*\)o\b/\1/g'
fue Hello Hello
pero para mí lo es Hello Hell
. Puedes corregir eso para
echo 'Hello Hello' | sed 's/\([^o]*\)o\b/\1/g'
pero
echo 'Hello Hello' | sed 's/o\b//g'
me parece mejor.
Respuesta2
Eliminar o
al final de las palabras es eliminar ao entre un carácter de palabra y un carácter que no es una palabra (o el EOL), por lo que:
sed -r 's/(\w)o(\W|$)/\1\2/g'
Respuesta3
Me pregunto si de alguna manera space
no es tu palabra delimitadora. Pruebe algo como lo siguiente:
$ echo hello hello | sed -e 's/o / /g;s/o$//'
hell hell
El problema con este ejemplo es que también tendrás que hacer lo mismo con .
y ,
cualquier otro delimitador de palabra. Coincidencia o
seguida de otro carácter específico con []
me gusta o[ \.,]
. Por alguna razón, esto no funciona para EOL $
, así que agregue otra cadena de búsqueda con ;
. Ejemplo:
$ echo hello hello, hello. toot hello | sed -e 's/o\([ \.,]\)/\1/g;s/o$//'
hell hell, hell. toot hell
$ echo $SHELL
/bin/bash
$ sed --version
sed (GNU sed) 4.4
$ set | grep IFS
IFS=$' \t\n'
Respuesta4
He probado esto con todos los símbolos de anclaje que se me ocurren.
No son las anclas, sino el hecho de que tienes una coincidencia codiciosa con el asterisco. La \(.*\)o
expresión coincideuna cuerda tan larga como pueda, por lo que se comerá todo hasta elúltimo o
. Podría coincidir con el anterior o
también.
Pero entonces, capturar algo y luego devolverlo es inútil, simplemente puedes eliminar el \(.*\)
y el \1
por completo.
Entonces, estos (al menos en GNU sed) eliminarían o
's' al final de las palabras:
sed 's/o\>//g'
sed 's/o\b//g'
Esto, por supuesto, sólo al final de la cadena:
sed 's/o$//g'
Y esto eliminará un o
, junto con el siguiente carácter que no es una palabra (por ejemplo, el espacio después de Hello
):
sed 's/o\W//g'
Si sed
no es compatible con \<
/ \>
o \b
, tendrá que hacer otra cosa. Esto coincidiría o
seguido de un carácter no alfanumérico o el final de la línea:
$ echo "jello, jello" | sed -E -e 's/o([^[:alnum:]]|$)/\1/g'
jell, jell
Esto funciona, por ejemplo, en el sed
que viene con OS X/macOS.
Las expresiones regulares de Perl admiten agregar un signo de interrogación *
o +
hacerlas no codiciosas. Entonces coincidirían con elmás cortocadena posible:
echo "jello, jello" | perl -pe 's/(.*?)o/$1/g'
jell, jell