Como fazer um (sed) regex substituindo todas as ocorrências de um caractere ao deletar o último?

2

Estou lutando com o seguinte. Estou usando comandos como este no meu terminal Mac para testar meu regex:

echo 'inputstring' | sed (-E) '/s///g'

Estou tentando criar um regex que:

  • se e somente se uma palavra terminar na letra 'o', então:
  • exclui essa palavra final 'o'
  • substitui todas as ocorrências da letra 'i' por 'a' nesta palavra

Nesse caso, o inputstring é filo fililo felo fale e a saída esperada é fal falal fel fale

Eu posso fazer um regex que faça a exclusão ou a substituição, mas não veja como combiná-los. Se eu colocar uma semi coluna entre eles, não vejo como colocar na parte condicional.

Eu também estou tendo problemas para definir a posição 'o fim da palavra'. Eu usei \b , mas parece que não funciona (ao contrário de $ para o final da string).

    
por Triplesmeg 19.11.2017 / 21:25

3 respostas

1

O

Awk seria mais preciso e flexível para esse caso:

awk '{ for(i=1;i<=NF;i++) 
       if ($i~/o$/) { sub(/o$/,"",$i); gsub("i","a",$i) } }1' <<<"filo fililo felo fale"

A saída:

fal falal fel fale

Abordagem de linha de comando alternativa Python :

python -c 'import sys,re; s = sys.stdin.read().strip(); 
print(re.sub(r"\b(\S+)o\b", lambda m: m.group(1).replace("i","a"), s))' <<<"filo fililo felo fale"
fal falal fel fale
    
por 19.11.2017 / 21:57
1

Eu não usaria sed para isso, mas se este for um exercício para aprender sed , faça um loop como este:

sed -E 's/$/ /
  :a
  s/i([[:alnum:]]*o[^[:alnum:]])/a/
  ta
  s/([[:alnum:]]*)o([^[:alnum:]])//
  ta
  s/ $//'
  • Na primeira linha, adiciono um espaço em branco no final, para que possamos tratar o final da linha como qualquer final de palavra. A última linha remove esse espaço em branco mais tarde.
  • O comando s na linha 3 procura ocorrências de i em uma palavra que termina com o e a substitui por a . O comando t faz um loop de volta para marcar :a para repetir isso para todas as i em todas as palavras de o .
  • Agora a quinta linha remove o final o e outro loop. Observe que, de uma palavra que termina com oo , ambas serão removidas; Não está claro se isso é desejado.

Apenas para referências, eu uso uma versão sed suportando a opção o para o comando s , o que significa apenas preservar a parte correspondente e descartar o resto. Também conhece o \h na substituição para substituir pelo conteúdo do espaço de espera. Isso faz da tarefa um one-liner:

sed -E ':a;h;s/([[:alnum:]]*)o($|[^[:alnum:]])//o;T;y/i/a/;x;s//\h/;ba'
    
por 20.11.2017 / 09:30
0

Eu não tenho certeza se isso é possível fazer com sed (eu suspeito que provavelmente não é), mas é muito fácil de fazer com o Python! Aqui está um script que faz exatamente o que você quer:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""modify_strings.py"""

import sys
import re
import fileinput

# Iterate over lines of input
# (either read from files or from stdin)
for line in fileinput.input():

    # Split each line into tokens and preserve whitespace
    tokens = re.split(r'(\s+)', line)

    # Iterate over tokens
    for token in tokens:

        # If a word ends in 'o' then
        # perform the desired transformation
        if token.endswith('o'):
            token = token[:-1].replace('i', 'a')

        # Print out each token
        sys.stdout.write(token)

Você pode executá-lo assim:

echo 'filo fililo felo fale' | python modify_strings.py

E produz a seguinte saída (conforme desejado):

fal falal fel fale

Se você realmente quer que sed esteja envolvido, então provavelmente você pode conseguir o que quer, aumentando-o com um pequeno script de shell. Isso pode ser parecido com o seguinte script bash :

#!/usr/bin/env bash

# modify-strings.bash

for word in "$@"; do
    if grep -q 'o$' <<<"${word}"; then
        echo -n "${word} " | sed -e 's/i/a/g' -e 's/o$//';
    else
        echo -n "${word} ";
    fi;
done
echo

Você chamaria esse script assim:

bash modify-strings.bash filo fililo felo fale
    
por 19.11.2017 / 21:51