Intentando eliminar caracteres finales de palabra con sed regex

Intentando eliminar caracteres finales de palabra con sed regex

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 Hellopero 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 oal 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 spaceno 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 oseguida 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 \(.*\)oexpresión coincideuna cuerda tan larga como pueda, por lo que se comerá todo hasta elúltimo o. Podría coincidir con el anterior otambién.

Pero entonces, capturar algo y luego devolverlo es inútil, simplemente puedes eliminar el \(.*\)y el \1por 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 sedno es compatible con \</ \>o \b, tendrá que hacer otra cosa. Esto coincidiría oseguido 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 sedque 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

información relacionada