Substitua todas as ocorrências de padrão pelo primeiro grupo correspondente

2

Eu tenho que ir a partir disso:

text match$something_here and match$xxx blablabla
text match$something_else_here and match$xxx blablabla
...

para isso:

text match$something_here and match$something_here blablabla
text match$something_else_here and match$something_else_here blablabla
...

Então eu preciso alterar, para cada linha no meu arquivo, o xxx após a segunda ocorrência de match$ com o que quer que seja após a primeira ocorrência de match$ .

    
por Juan 07.02.2015 / 01:17

4 respostas

2
:%s/match\$\zs\(\w\+\)\(.*match\$\)xxx//

Explicação

  • match\$\zs : ancora a correspondência no primeiro match$ ; Eu uso \zs para começar a partida depois disso, para evitar outro grupo de captura
  • \(\w\+\) : captura o texto após a primeira ocorrência de match$
  • \(.*match\$\) : capture o que vem depois disso, até a segunda ocorrência de match$ , e capture como queremos mantê-lo
  • xxx : corresponde ao que é substituído

Substituição : o texto após a primeira ocorrência, depois o texto no meio e o primeiro texto novamente (substituindo o xxx ).

    
por 07.02.2015 / 11:26
1

Tente isto:

sed -e 's/\(match\$\)\([a-zA-Z_]\+\)\([a-zA-Z ]\+match\$\)[a-zA-Z]\+//' < input.txt > output.txt

Usando um input.txt de:

text match$something_here and match$xxx blablabla
text match$something_else_here and match$xxx blablabla

Eu recebo um output.txt de:

text match$something_here and match$something_here blablabla
text match$something_else_here and match$something_else_here blablabla
    
por 07.02.2015 / 01:47
1
:%s/\v(match\$(\w+).*match\$)xxx//
  • \ v muito mágico (podemos usar menos \\)
por 09.02.2015 / 19:00
1
sed -e 's/\(match\)\([_[:alnum:]]*\)\(\(.*\)\n\)*/\
/2;tc' -e b -e :c -e 's///'

A sequência acima sempre tratará apenas a primeira e a segunda ocorrência de match em uma linha - independentemente de quantos possam existir em uma linha.

Funciona fazendo a primeira s/// ubstitution na ocorrência de s///2 cd do padrão e, em seguida, se a substituição t ests for bem-sucedida, b ranching para o rótulo :c ontinue ou se não, b ranching fora do script.

Portanto, quando houver uma segunda correspondência do padrão, o padrão será repetido para o comando 2cd s/// ubstitution. Mas quando não há as linhas são impressas como de costume.

O importante é a subexpressão \(\(.*\)\n\)* . A subexpressão corresponde apenas a uma cadeia nula para o primeiro comando s///2 , porque um \n ewline só pode ocorrer em um espaço de padrão sed como resultado de uma edição. Mas quando o padrão for repetido, o \(\(.*\)\n\)* corresponderá a qualquer / todos os caracteres que ocorram entre os dois match es porque o s/// ubstitution anterior inseriu um \n ewline ao substituir [_[:alnum:]]* . E assim, o mesmo padrão repetido pode significar duas coisas diferentes, dependendo de seu contexto no script.

Embora a versão acima deva funcionar como escrita para qualquer POSIX sed (ênfase em deve - muitos sed s não obedecem a repetidos padrões de subexpressão) , com GNU sed você pode escrevê-lo um pouco mais curto:

sed -E 's/(match)(\w*)((.*)\n)*/\n/2;T;s///
' <<\IN
text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_xxx blablabla
text match_something_else_here and match_xxx blablabla
text match_something_here and match_xxx blablabla match_xxx blablabla
text match_something_else_here and match_xxx blablabla match_xxx blablabla match_xxx blablabla
IN

... O bit <<\IN a IN é apenas uma entrada do documento aqui para que eu possa demonstrar como funciona - você provavelmente deve usar <input_file em seu lugar. Observe também que mudei seu $something e $xxx para _something e _xxx porque entendo que esses sinais de dólar não devem ser incluídos no padrão de substituição, mas serão substituídos por outra coisa. Se for verdade, então você pode manter o \w* ord escapar lá, ou, se você quiser literalmente cifrões incluídos, então você ainda deve definir sua própria classe de caracteres e adicioná-la como: [$_[:alnum:]]* .

Observe que o tc' -e b -e :c -e é encurtado para - com o GNU sed - apenas um T . Enquanto portably o t est resultou em uma substituição bem-sucedida de b ranching no ponto em que as linhas malsucedidas b foram removidas, com GNU sed você pode T est para resultados sem sucesso - que ramifica-os diretamente e apenas as linhas restantes que ainda estão executando o script nesse ponto são aquelas que fizeram substituir com sucesso o segundo par de jogos por um \n ewline.

Em qualquer caso, (dependendo do sed ) qualquer um dos itens acima será impresso:

text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_something_here blablabla
text match_something_else_here and match_something_else_here blablabla
text match_something_here and match_something_here blablabla match_xxx blablabla
text match_something_else_here and match_something_else_here blablabla match_xxx blablabla match_xxx blablabla
    
por 09.02.2015 / 20:00