
Sou novo em regex e sed e estou tentando criar o que pensei que seria um regex simples: quero remover a letra final da palavra se for um 'o'.
- String de entrada: Olá Olá
- Resultado esperado: Inferno Inferno
A boa notícia: posso remover o 'o' quando estiver no final da string:
$ echo 'Hello Hello' |sed 's/\(.*\)o/\1/g'
Hello Hell
$ echo 'Hello Hello' |sed 's/\(.*\)o$/\1/g'
Hello Hell
A má notícia: não consigo removê-lo das palavras anteriores na string. Eu tentei isso com todos os símbolos de âncora que consigo imaginar. O resultado é que nenhum dos 'o's finais da palavra é removido:
$ 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
Você pode me ajudar a recuperar minha sanidade, me dizendo o que estou fazendo de errado?
Atualização: tenho a nítida impressão de que minha máquina produz resultados diferentes dos de outras pessoas. Estou usando a janela do terminal no meu Macbook. Se alguém puder lançar alguma luz sobre isso, por favor me diga.
Responder1
echo 'Hello Hello' | sed 's/o$//'
parece mais útil para mim do que o seu
echo 'Hello Hello' | sed 's/\(.*\)o$/\1/g'
Na sua pergunta diz que a saída de
echo 'Hello Hello' | sed 's/\(.*\)o\b/\1/g'
foi Hello Hello
, mas para mim é Hello Hell
. Você pode corrigir isso para
echo 'Hello Hello' | sed 's/\([^o]*\)o\b/\1/g'
mas
echo 'Hello Hello' | sed 's/o\b//g'
parece melhor para mim.
Responder2
Remover o o
no final das palavras é remover ao entre um caractere de palavra e um caractere não-palavra (ou EOL), portanto:
sed -r 's/(\w)o(\W|$)/\1\2/g'
Responder3
Estou me perguntando se de alguma forma space
sua palavra não é delimitadora. Tente algo como o seguinte:
$ echo hello hello | sed -e 's/o / /g;s/o$//'
hell hell
O problema com este exemplo é que você também terá que fazer o mesmo para .
ee ,
qualquer outro delimitador de palavra. Correspondência o
seguida por outro caractere específico com []
like o[ \.,]
. Por algum motivo, isso não funciona para EOL $
, então adicione outra string de pesquisa com ;
. Exemplo:
$ 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'
Responder4
Eu tentei isso com todos os símbolos de âncora que consigo imaginar.
Não são as âncoras, mas o fato de você ter uma correspondência gananciosa com o asterisco. A \(.*\)o
expressão correspondeuma corda tão longa quanto possível, então ele vai comer tudo até odurar o
. Pode corresponder o
aos anteriores também.
Mas então, capturar algo e depois devolvê-lo é inútil, você pode simplesmente remover o \(.*\)
e o \1
completamente.
Então, estes (pelo menos no GNU sed) removeriam o
's no final das palavras:
sed 's/o\>//g'
sed 's/o\b//g'
Isso, claro, apenas no final da string:
sed 's/o$//g'
E isso removerá um o
, junto com um seguinte caractere que não seja de palavra (por exemplo, o espaço depois de Hello
):
sed 's/o\W//g'
Se você sed
não suportar \<
/ \>
ou \b
, você terá que fazer outra coisa. Isso corresponderia o
seguido por um caractere não alfanumérico ou pelo final da linha:
$ echo "jello, jello" | sed -E -e 's/o([^[:alnum:]]|$)/\1/g'
jell, jell
Isso funciona, por exemplo, no sed
que vem com o OS X/macOS.
As expressões regulares Perl suportam a adição de um ponto de interrogação *
ou +
para torná-las não gananciosas. Então eles combinariammais curtosequência possível:
echo "jello, jello" | perl -pe 's/(.*?)o/$1/g'
jell, jell