A substituição do padrão após a enésima partida é encontrada em cada linha? [duplicado]

5

Eu tenho um arquivo contendo linhas:

india;austria;japan;chile
china;US;nigeria;mexico;russia

Eu quero substituir todas as ocorrências de ponto e vírgula em cada linha com, e. ;NEW; , mas a partir da segunda ocorrência apenas. O resultado deve ser assim:

india;austria;NEW;japan;NEW;chile
china;US;NEW;nigeria;NEW;mexico;NEW;russia

Eu tentei isso com o gsub, mas ele substitui todas as ocorrências:   awk '/;/{gsub(/;/,";NEW;") }{print}'

    
por munish 18.03.2013 / 11:46

4 respostas

8

A solução awk é muito mais longa, mas é mais fácil torná-la genérica:

awk -F\; '{for(i=1;i<NF;i++)printf"%s;%s",$i,(i>=2)?"NEW;":"";print$NF}' replacefile

É possível fazer isso com sed também, fazendo um loop com o comando t e sempre substituindo o segundo separador (ou o que você quiser) em alguma marca temporária (geralmente \n ):

sed ':b;s/;/\n/2;tb;s/\n/;NEW;/g' replacefile
    
por 18.03.2013 / 12:01
8

Há um sinalizador para o comando s/// do sed do GNU que faz isso:

sed 's/;/;NEW;/2g' <<END
india;austria;japan;chile
china;US;nigeria;mexico;russia
END

saídas

india;austria;NEW;japan;NEW;chile
china;US;NEW;nigeria;NEW;mexico;NEW;russia

Consulte o link

The s command can be followed by zero or more of the following flags:

g

Apply the replacement to all matches to the regexp, not just the first.

     

número

     

Only replace the numberth match of the regexp. Note: the posix standard does not specify what should happen when you mix the g and number modifiers, and currently there is no widely agreed upon meaning across sed implementations. For GNU sed, the interaction is defined to be: ignore matches before the numberth, and then match and replace all matches from the numberth on.

     

...

(ênfase minha)

    
por 18.03.2013 / 13:57
1

Eu faria isso em duas etapas:

Primeiro, substitua todos os pontos-e-vírgulas por ;NEW; :

sed -e s/\;/\;NEW\;/g

Em seguida, substitua o primeiro ;NEW; por um ponto e vírgula:

sed -e s/\;NEW\;/\;/

Você pode usar um pipe para fazer as duas substituições em uma linha. Aqui está um exemplo:

$ more replacefile 
india;austria;japan;chile;
china;US;nigeria;mexico;russia
$ cat replacefile |sed -e s/\;/\;NEW\;/g  |sed -e s/\;NEW\;/\;/
india;austria;NEW;japan;NEW;chile;NEW;
china;US;NEW;nigeria;NEW;mexico;NEW;russia
    
por 18.03.2013 / 11:53
1

Eu posso fazer isso com mais código, mas sem loops!

Dados

china;US;nigeria;mexico;russia
iindia;austria;japan;chile

Script

BEGIN{ FS=";" }{
    insert=$param
    ix=index($0, insert) + length(insert)

    if (NF <= $param) {
            rest = substr($0,ix,length($0))
            gsub(";",";NEW;",rest)
            line = substr($0,0,ix) rest

            gsub(";;",";",line)
            gsub(";$","",line)
            print line

} else {print}}

Exemplo

 Microknoppix v # awk -f replaceNth.awk -v param=2 countries
 china;US;NEW;nigeria;NEW;mexico;NEW;russia
 iindia;austria;NEW;japan;NEW;chile
    
por 18.03.2013 / 13:02