Gostaria de realizar uma pesquisa e substituir em um arquivo por 12000 linhas.
Especificamente, se ^ SetFontSize 28
existir uma ocorrência após um ^Hide
bloco e antes do próximo ^Hide
ou ^Show
, mude 28
para 18
.
Aqui está um trecho do arquivo original.
Hide # Gear - Endgame
ItemLevel >= 77
Rarity = Magic
LinkedSockets >= 3
BaseType "Runic Hatchet"
SetTextColor 140 190 255 # Magic Item Highlight
SetFontSize 28
Hide # Gear - Endgame
ItemLevel >= 77
Rarity = Magic
Sockets >= 3
BaseType "Runic Hatchet"
SetTextColor 140 190 255 # Magic Item Highlight
SetFontSize 28
Show # Gear - Endgame
ItemLevel >= 83
Rarity = Normal
Sockets < 3
BaseType "Tiger Hook"
SetTextColor 240 240 240 # Normal Item Highlight
SetBackgroundColor 70 70 70
SetFontSize 28
O resultado final de um dos Hide
blocos deve ficar assim:
Hide # Gear - Endgame
ItemLevel >= 77
Rarity = Magic
LinkedSockets >= 3
BaseType "Runic Hatchet"
SetTextColor 140 190 255 # Magic Item Highlight
SetFontSize 18
Substituindo SetFontSize 28
para SetFontSize 18
, mas apenas se ele aparecer em um ^Hide
bloco.
O regex desagradável que tentei foi:
:%s/^Hide\(.*\)SetFontSize 28$/Hide\1SetFontSize 18/g
Mas foi dito que o padrão não foi encontrado. Informe-me se alguma informação adicional é necessária ou se minha solicitação não está clara.
Hide
bloco tem umaSetFontSize
linha (qualquer que seja o valor)? Em caso afirmativo, você poderia usar #:%s/Hide\_.\{-\}SetFontSize \zs28/18/
whatever be the value
causaria problemas, sua solução só funciona se cadaHide
bloco tiver umaSetFontSize
linha e seu valor for exatamente28
, caso contrário, ele corresponderá até28
outro bloco.Respostas:
Uma maneira de resolver isso seria usar o
:global
que gera uma saída de faixa.O uso típico do
global
comando seriaEle também tem a opção de fazer esse padrão gerar um intervalo, em vez de uma correspondência de linha única, usando
,
o formato deIsso gera um intervalo que é aplicado ao comando.
Para o seu exemplo, o primeiro padrão seria combinar a primeira
Hide
entrada e o segundo padrão ou éHide
,Show
ou o fim do arquivo (supondo que você quer que a última Esconder caso).O primeiro regex é simples
/Hide/
,. O segundo regex contém algumas partes interessantes.\(
e\)
cria um agrupamento de átomos para corresponder\|
é a operação OU\%$
representa o final do arquivoDepois de definirmos nossos intervalos, aplicamos substituto com um padrão e uma sequência como você faria normalmente.
Observe que o regex usado neste exemplo é muito básico. Você quer ter certeza de que seus identificadores para o início e o fim do intervalo capturem as áreas certas.
fonte
Parece que o seu desagradável regex não foi suficiente desagradável ... :-)
Seção de Pesquisa
A pesquisa teria que ser alterada para isso:
Isso inclui algumas coisas incomuns e tantos parênteses ... Vamos ver o que temos lá:
O sinal de intercalação (
^
)O sinal de intercalação é usado para significar o início da linha. Acho que já estamos familiarizados com este.
Um ponto importante, o
^
não funciona, exceto como o primeiro caractere em seu padrão. Após o que é tomado literalmente. Para incluir um início de linha em sua expressão, você precisa usar\_^
. No entanto, em nossa situação, não precisamos disso.(Há um fenômeno semelhante com
$
e\_$
)O primeiro e o último parênteses (
\( ... \)
)O primeiro e o último parênteses são usados por si próprios, o que significa que ele pega o que aparece dentro e o define como parâmetro
\1
. Você já usou isso em seu próprio regex, portanto, assumirei que você também esteja familiarizado com este.O segundo conjunto de parênteses
Como você pode notar, há um segundo conjunto de parênteses seguido por um asterisco
\( ... \)*
. Isso significa que estamos procurando o que corresponder inúmeras vezes. Essa é a maneira usual de usar o asterisco, para que você esteja familiarizado com ele.O terceiro conjunto de parênteses, OR e
\_.
Sim, na verdade existem três parênteses antes da palavra
Show
. Este último conjunto é necessário por dois motivos: o\|
e o seguinte@!
.Em relação à operação OR, você já deve estar familiarizado com ela.
O pedido não importa aqui. O
\
é necessário na frente do|
para trabalhar no vim.Os parênteses em torno dessa expressão nos permitem seguir a expressão de alguma forma . Aqui o
@!
.Este é muito menos familiar. Significa se não for correspondido . Porém, o uso disso não é muito fácil, mas você precisa seguir essa expressão com o que deseja extrair, o que não deve corresponder à expressão. É por isso que temos
\_.
por trás desse padrão.Os
\_.
meios correspondem a qualquer coisa. Ao contrário do que é o.
próprio, o que não corresponde ao\n
personagem. Em outras palavras, correspondemos a qualquer caractere em qualquer número de linhas, a menos que corresponda aShow
ouHide
.Observe que os parênteses em torno dessa expressão também são importantes, assim como o asterisco, portanto, é exatamente isso que a faz funcionar:
aka coincidir com o que quer para o próximo
Show
ouHide
caracteres (note que ele também iria corresponderShowing
,Shower
,HideMe
, etc. você deve ser capaz de usar\<
e\>
, se for necessário para coincidir com a palavra exatamente.)Nota lateral: para pesquisar em várias linhas, também é possível usar o
\n
caractere no padrão. No entanto, não é tão versátil quanto o\_.
padrão.SetFontSize 28
Agora a seção também precisa incluir
SetFontSize 28
. Assim como você teve no seu regex. Se nãoSetFontSize 28
aparecer nessa seção, tente a pesquisa novamente na próxima seção.Devido à negação acima (a correspondência exceto
Show
ouHide
), a pesquisa não vaza para a próxima seção, correndo o risco de estragar tudo.Seção de substituição
A substituição é igual à sua:
Usamos os parênteses na pesquisa para que
\1
funcione conforme o esperado.Pesquisa completa e substituição
Os padrões resultantes são assim:
O
\(Show\|Hide\)
deve incluir todos os cabeçalhos possíveis .Fontes
Regex para corresponder a qualquer caractere, incluindo nova linha (
\_.\{-}
)Procure linhas que não contenham padrão e outras pesquisas úteis (
@!
)Documentação do Vim: pattern (
\_^
)fonte
()*
, minha versão de sua resposta:%s/\v^Hide.*\n(\s+.*\n)*\s*SetFontSize\s+\zs28/16
.