Como substituir o conteúdo entre dois padrões do arquivo?

9

Eu tenho o seguinte formato do arquivo:

<common>
fitnes=0
genetic=1
method=0
</common>
<inputs>
foo=bar
bar=foo
</inputs>
<limits>
balance=200.00
</limits>

e eu gostaria de excluir tudo o que está entre <inputs>e </inputs>(excluindo o padrão próprio) e substituí-lo pelo conteúdo de outro arquivo (por exemplo foo.txt). Em outras palavras, as linhas com foo=bare bar=fooseriam substituídas por outro conteúdo.

Provavelmente, pode ser semelhante à maneira como você exclui uma correspondência de várias linhas , como:

:g/<inputs/,/inputs>/d

mas não tenho certeza com o que devo substituir dpara inserir o conteúdo de outro arquivo, mas quero manter o padrão correspondente.

Uma abordagem semelhante seria remover o conteúdo interno da tag html , como

:/<inputs>/norm vitd

mas não sei como você adicionaria o conteúdo do arquivo.

Idealmente, estou tentando encontrar um liner, pois ele fará parte de outro script.

Como posso conseguir isso?

kenorb
fonte

Respostas:

10

Uma substituição pode ser usada para substituir um padrão pelo resultado de uma expressão como esta:

:keeppatterns %s;<inputs>\zs\_.\{-}\ze</inputs>;\=insert(readfile('test.txt'), '')

Vejo :help sub-replace-expression

Observe que keeppatternsimpede o substitutecomando de adicionar qualquer coisa ao histórico de pesquisa e preserva o "último registro de padrão de pesquisa" - consulte :help "/. É uma boa prática para evitar scripts a partir desnecessariamente modificar o estado global da Vim com os modificadores de comando keepalt, keepjumps, lockmarks, keepmarks, e keeppatterns.

djjcast
fonte
5

Uma abordagem alternativa à de Gary é a seguinte:

:g/^<inputs>/+,/^<\/inputs>/-d|-r dummy

O qual primeiro exclui tudo no padrão fornecido, e usa o :rcomando para ler os dados do manequim de arquivo. Agora, se você precisar extrair o nome do arquivo das linhas entre o <input>/</input>padrão, isso ficará um pouco mais complicado.

Christian Brabandt
fonte
4

Isso parece funcionar, pelo menos em um sistema Unix:

:/<inputs>/+1,/<\/inputs>/-1!cat foo.txt

Ele usa o {range}!{filter}comando para filtrar as linhas de um depois <inputs>para um antes </inputs>através do programa externo cat foo.txt. Nesse caso, catignora sua entrada padrão, para que as linhas originais sejam excluídas e substituídas pelo conteúdo do arquivo foo.txt.

Vejo:

:help :range!
:help cmdline-ranges
garyjohn
fonte
2

Eu sinto que uma macro será uma abordagem mais fácil. Especialmente, se você tiver vários lugares para fazer o mesmo.

  1. Mantenha apenas esses 2 arquivos abertos.
  2. Agora, no primeiro arquivo, comece a gravar por qa,( aé o nome do registro).
  3. Pesquise o padrão inicial, pressione para baixo e pressione Ctrl- v, pesquise o padrão final, pressione para cima . Agora a parte que você deseja excluir está selecionada. Delete isso.
  4. Marque a posição usando ma( aé o nome da marca) e salve o arquivo.
  5. Vá para o 2º arquivo, por :b2comando e selecione da mesma forma a peça de acordo com seus critérios de início / fim.
  6. Volte a este arquivo e pressione apara ir para esse ponto. Cole lá por p.
  7. Procure o critério final novamente e atravesse a seção para não atingi-lo novamente.
  8. Saia da gravação pressionando q.
  9. Repita o número de vezes por 40@a.
Krishanu Banerjee
fonte
11
Obrigado pela sugestão, tudo bem, mas não ajudará nesse caso específico, pois estou procurando uma solução não interativa como parte do exscript onde posso especificar qual arquivo inserir, dependendo dos argumentos de entrada do usuário.
Kenorb # 02/02
1

Se essa é outra tentativa de analisar XML com ferramentas não XML, não faça isso.

As soluções aqui são válidas, mas a intenção pode não ser. Se o XML não for de uma fonte bem domesticada, você poderá obter escapes, CDATA ou espaços em branco na tag!

Portanto, o xsltproc do comando no vi pode lidar com isso.

Matthias Š
fonte
O arquivo não é realmente um formato XML adequado, mas na verdade não é um iniarquivo bem documentado com essas três tags semelhantes a XML.
Kenorb # 02/02