Remove um caractere entre 2 strings conhecidas

4

Eu tenho um conjunto de dados como abaixo:

\"XXX \ START sapiodj \" aj \d 2387 END hddo\" START bbcc  \" END ss

Meu requisito: Desejo remover todas as ocorrências de barra invertida \ e aspas duplas " entre START e END.

Saída desejada:

\"XXX \ START sapiodj  aj d 2387 END hddo\" START bbcc   END ss

Nota:

  1. Múltiplo START / END na mesma linha
  2. Desejo remover \ e " apenas entre START e END e em nenhum outro lugar
  3. E meu arquivo tem várias linhas (linhas semelhantes às mostradas acima)
  4. preciso usar sed

Eu tentei algo como abaixo (estava tentando se livrar de " alone primeiro) e isso não me deu o resultado desejado:

sed '/START/,/END/ s/"//g'
    
por Sujay Kulkarni 18.12.2014 / 10:06

4 respostas

3

Supondo que você não tenha o caractere ' no arquivo. Se você acabou de alterar na linha abaixo todos os ' para qualquer outro personagem que com certeza não estará presente na entrada.

sed -e 's/END/'/g;:X' -e 's/\(START[^']*\)["\]//g;tX' -e 's/'/END/g'
    
por 18.12.2014 / 11:32
2

Não é muito difícil com sed realmente. Você sempre pode delimitar uma seção com um \n ewline ou para trocar um delimitador por \n ewline temporariamente. E você pode fazer isso sem um loop:

sed 's/$/START/;s/END/&
/g;  y/D\n/\nD/
     s/\([^D]*START\)*[D\"]*//g
     y/\n/D/;s/.....$//
' <<\IN                                           
\"XXX \ START sapiodj \" aj \d 2387 END hddo\" START bbcc  \" END ss
IN

Às vezes você só precisa pensar em um problema de maneira um pouco diferente. Em vez de remover todo o \" entre START e END se, em vez disso, mudarmos o problema para a forma como podemos economizar \" apenas se ocorrerem entre o início da linha e START , START e END strings, e o último END e o final da linha fica um pouco mais fácil (se, reconhecidamente, não intuitivamente) . Isso ocorre devido à maneira como sed processa * zero ou mais correspondências em g lobal s/// contexto de ubstitution .

Enquanto oSTART de head-to-first-% será eliminado como resultado natural do restante, o últimoEND -to-tail não - e, portanto, precisamos acrescentar outro START para o final da linha. Depois de obtermos nosso START extra, acrescentamos um caractere \n ewline a cada ocorrência de END . E, em seguida, com o comando y/// transliterate, negociamos simultaneamente todos os D chars para \n ewlines e vice-versa. O comando y/// transliteration, aliás, não é apenas muito útil aqui, mas também é mais eficiente do que um s/// ubstitution seria.

Neste momento, um l ook no nosso espaço padrão seria impresso:

\"XXX \ START sapiodj \\" aj \d 2387 EN\nD hddo\" START bbcc  \\" EN\nD ssSTART$

Como você pode ver, agora todos os caracteres de \" que precisam ser salvos estão exatamente entre o início da linha ou as sequências D e START e não há D s entre elas. Portanto, a g lobal s/// ubstitution que remove os caracteres indesejados - para incluir nosso D s adicional - também substitui os que precisam ser salvos com eles mesmos. Por último, precisamos apenas trocar \n e D s novamente e remover o último START .

Desta forma, você pode delimitar de forma confiável os campos com sed independentemente da entrada e você não precisa depender de nenhum caractere que não ocorra, mas o que é garantido nunca ocorrer em uma linha - e esse é o caractere \n ewline, é claro.

Quando terminar, imprime:

\"XXX \ START sapiodj  aj d 2387 END hddo\" START bbcc   END ss
    
por 19.12.2014 / 05:42
1

com sed :

sed 's/:/::/g;s/</:l/g;s/>/:g/g; # escape :, <, >
     s/START/&</g; s/END/>&/g;   # replace START/END with <>
     :1
     s/\(<[^>]*\)[\"]//g;t1
     s/[<>]//g;s/:g/>/g;s/:l/</g;s/::/:/g; # restore <>:'

com perl :

perl -pe's|START.*?END|$&=~y/\"//rd|ge'
    
por 18.12.2014 / 11:11
0

Você tem indicado em um comentário que awk também é permitido. Então estou baseando minha resposta nisso.

Assumindo que START s e END s sejam balanceados, se você dividir a linha em uma das duas palavras, descobrirá que deseja remover barras invertidas e aspas duplas de todos os campos pares. Para este fim:

awk -F 'START|END' '{
                      for(i=2;i<=NF;i+=2){ # For each even-numbered field
                        gsub(/["\]/,"",$i) # Remove " and \ from it
                        $i="START"$i"END" # Put START and END back around it
                      }
                    }' your_file

Isso pressupõe que sua implementação de awk tenha a função gsub que não posso garantir.

Como observação, seu sed não funciona porque está basicamente dizendo "aplique a substituição ao intervalo de linhas que começa com uma linha correspondente a START e termina com uma linha correspondente a END ". / p>     

por 18.12.2014 / 10:52