Recherche et remplacement multiligne

9

Voudrait effectuer une recherche et remplacer dans un fichier de 12000 lignes.

Plus précisément, si une occurrence de ^ SetFontSize 28existe après un ^Hidebloc et avant le suivant ^Hideou ^Show, passez 28à 18.

Voici un extrait du fichier d'origine.

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

Le résultat final pour l'un des Hideblocs devrait ressembler à ceci:

Hide # Gear - Endgame
    ItemLevel >= 77
    Rarity = Magic
    LinkedSockets >= 3
    BaseType "Runic Hatchet"
    SetTextColor 140 190 255 # Magic Item Highlight
    SetFontSize 18

Remplacement SetFontSize 28de SetFontSize 18, mais uniquement s'il apparaît dans un ^Hidebloc.

Le regex méchant que j'ai essayé était: :%s/^Hide\(.*\)SetFontSize 28$/Hide\1SetFontSize 18/g

Mais on m'a dit que le motif n'était pas trouvé. Veuillez me faire savoir si des informations supplémentaires sont nécessaires ou si ma demande n'est pas claire.

Gars
la source
5
Chaque Hidebloc a-t-il une SetFontSizeligne (quelle que soit la valeur)? Si c'est le cas, vous pouvez utiliser:%s/Hide\_.\{-\}SetFontSize \zs28/18/
muru
2
@muru whatever be the valuecauserait des problèmes, votre solution ne fonctionne que si chaque Hidebloc a une SetFontSizeligne et sa valeur est exactement 28, sinon, elle correspond jusqu'à 28un autre bloc.
dedowsdi

Réponses:

3

Une façon de résoudre ce problème serait d'utiliser :globalun générateur de sortie de plage.

L'utilisation typique de la globalcommande serait

:[range]g/{pattern}/[cmd]

Il a également la possibilité de faire en sorte que ce modèle génère une plage plutôt qu'une correspondance sur une seule ligne en utilisant ,sous la forme de

:[range]g/{first pattern}/,/{second pattern}/[cmd]

Cela génère une plage qui est appliquée à la commande.

Pour exemple , le premier motif serait assortit la première Hideentrée et le second motif est soit Hide, Showou la fin du fichier ( en supposant que vous voulez que le dernier cas Masquer).

:g/Hide/,/\(Hide\|Show\|\%$\)/s/SetFontSize 28/SetFontSize 18/

La première regex est simple, /Hide/. Le deuxième regex contient quelques parties intéressantes.

  • \(et \)crée un groupement d'atomes pour correspondre
  • \| est l'opération OU
  • \%$ représente la fin du fichier

Une fois que nous avons défini nos plages, nous appliquons le substitut avec un modèle et une chaîne comme vous le feriez normalement.

Veuillez noter que l'expression régulière utilisée dans cet exemple est très basique. Vous voudrez vous assurer que vos identifiants pour le début et la fin de la plage capturent les bonnes zones.

jecxjo
la source
3

Il semble que votre regex méchant n'était pas assez méchant ... :-)

Section de recherche

La recherche devrait être modifiée comme suit:

^Hide\(\(\(Show\|Hide\)\@!\_.\)*\)SetFontSize 28

Cela inclut pas mal de choses rares et tant de parenthèses ... Voyons ce que nous avons là-dedans:

Le curseur ( ^)

Le caret est utilisé pour signifier le début de la ligne. Je pense que nous connaissons déjà celui-ci.

Un point important, le ^ne fonctionne que comme le tout premier caractère de votre modèle. Après cela, il est pris mot pour mot. Pour inclure un début de ligne dans votre expression, vous devez utiliser \_^. Cependant, dans notre situation, nous n'en avions pas besoin.

(Il y a un phénomène similaire avec $et \_$)

La première et la dernière parenthèse ( \( ... \))

La première et la dernière parenthèse sont utilisées seules, ce qui signifie qu'il saisira tout ce qui apparaît à l'intérieur et le définira en paramètre \1. Vous l'avez déjà utilisé dans votre propre expression régulière, donc je suppose que vous connaissez également celui-ci.

Le deuxième ensemble de parenthèses

Comme vous pouvez le remarquer, il existe un deuxième ensemble de parenthèses suivi d'un astérisque \( ... \)*. Cela signifie que nous recherchons ce qui correspond un certain nombre de fois. Il s'agit de la manière habituelle d'utiliser l'astérisque, vous devez donc le connaître.

Le troisième ensemble de parenthèses, OR, et \_.

Oui, il y a en fait trois parenthèses devant le mot Show. Ce dernier ensemble est nécessaire pour deux raisons: la \|et la suivante @!.

En ce qui concerne l'opération OR, vous devez déjà la connaître.

Show\|Hide    or    Hide\|Show

L'ordre n'a pas d'importance ici. Le \est nécessaire devant le |pour travailler en vim.

La parenthèse autour de cette expression nous permet de suivre l'expression par quelque chose . Voici le @!.

\(Show\|Hide\)@!

Celui-ci est beaucoup moins familier. Cela signifie que s'il ne correspond pas . L'utilisation de ceci n'est cependant pas très facile, mais vous devez suivre cette expression avec ce que vous voulez extraire qui ne devrait pas correspondre à ladite expression. C'est pourquoi nous avons \_.derrière ce modèle.

Les \_.moyens correspondent à quoi que ce soit. Contrairement au .seul, qui ne correspond pas au \npersonnage. En d'autres termes, nous faisons correspondre n'importe quel caractère sur un nombre quelconque de lignes, sauf s'il correspond à Showou Hide.

Notez que les parenthèses autour de cette expression sont également importantes, tout comme l'astérisque, donc tout cela est vraiment ce qui le fait fonctionner:

\(\(Show\|Hide\)@!\_.\)*

alias correspondent tout à la suivante Showou les Hidecaractères (notez que ce serait également correspondre Showing, Shower, HideMe, etc. , vous devriez être en mesure d'utiliser \<et \>s'il est nécessaire de faire correspondre exactement le mot.)

Note latérale: pour rechercher sur plusieurs lignes, il est également possible d'utiliser le \ncaractère dans le motif. Cependant, ce n'est pas aussi polyvalent que le \_.motif.

SetFontSize 28

Maintenant, la section doit également inclure SetFontSize 28. Tout comme vous l'aviez dans votre expression régulière. Si aucun SetFontSize 28n'apparaît dans cette section, essayez à nouveau la recherche dans la section suivante.

En raison de la négation ci-dessus (la correspondance sauf Showou Hide), la recherche ne passe pas à la section suivante, prenant le risque de la gâcher.

Section de remplacement

Le remplacement est le même que vous l'aviez:

.../Hide\1SetFontSize 18/

Nous utilisons les parenthèses dans la recherche pour que les \1travaux fonctionnent comme prévu.

Recherche complète et remplacement

Les modèles résultants se présentent comme suit:

:%s/^Hide\(\(\(Show\|Hide\)@!\_.\)*\)SetFontSize 28/Hide\1SetFontSize 18/

Le \(Show\|Hide\)devrait inclure tous les en- têtes possibles .

Sources

Regex pour correspondre à n'importe quel caractère, y compris la nouvelle ligne ( \_.\{-})

Recherche de lignes ne contenant pas de motif et autres recherches utiles ( @!)

Documentation Vim: pattern ( \_^)

Alexis Wilke
la source
1
J'aime la ()*, ma version de votre réponse: %s/\v^Hide.*\n(\s+.*\n)*\s*SetFontSize\s+\zs28/16.
dedowsdi