Convertir sed regex en vim regex

Sep 09 2020

J'ai cette regex sed que j'ai trouvée:

sed '/start/!d;s//&\n/;s/.*\n//;:a;/end/bb;$!{n;ba};:b;s//\n&/;P;D'

qui produit essentiellement le contenu entre un point de départ et un point final.

##1##
this is a test
with multiple
line
##z##

et le remplacement startavec ##1##et endpour ##z##cela donner:


this is a test
with multiple
line

S'il y a plusieurs occurrences du ##1##et ##z##, alors il afficherait évidemment tout le texte intermédiaire de ladite occurrence, comme ceci:

##1##
this is a test
with multiple
line
##z##
##1##
this is a test
with multiple
line
##z##

à


this is a test
with multiple
line


this is a test
with multiple
line

Pour clarifier encore plus:

##1##
this is a test
with multiple
line
##z##
##2##
test
##z##

ne donnerait évidemment que ce qui est spécifié comme point de départ (puisque le point final ##z##est toujours le même). Donc, si j'utilise à la ##2##place comme point de départ:


test

Cela donnerait ce qui précède comme sortie.

Mon objectif est de convertir ceci en une expression régulière compatible pour vim. J'utilise ce site et le manuel local comme aide, mais je ne sais pas par où commencer pour convertir ce qui précède en vim regex.

Réponses

2 D.BenKnoble Sep 10 2020 at 03:16

Une fonction extrêmement simple qui fait le travail de manière beaucoup plus idiomatique:

function! Between(start, end) abort
  let [start_line, _] = searchpairpos(a:start, '', a:end, 'bWn')
  let [end_line, _] = searchpairpos(a:start, '', a:end, 'Wn')
  if start_line is# 0 || end_line is# 0
    return
  endif
  call setline(start_line, '') " or: execute start_line 'delete'
  call setline(end_line, '') " or: execute end_line 'delete'
endfunction

Nommez-le comme vous voulez, puis faites, par exemple,

call Between('##1##', '##z##')

(que vous pourriez peut-être lier à une clé).

Pour travailler sur l'ensemble du fichier, vous pouvez peut- être utiliser :global(ou même simplement :%call Between(...)), ou vous pouvez avoir besoin d'une boucle enveloppant cette fonction et parcourant le fichier. Dans le cas de ce dernier, j'utiliserais search(a:start)pour trouver le prochain début et ensuite +pour être à l'intérieur de la région imbriquée; alors j'appellerais la fonction. C'est plus rapide que d'appeler la fonction sur chaque ligne.

3 Quasímodo Sep 10 2020 at 04:17
:g/END\|\%^/,/START\|\%$/s/.*//

Cette commande globale marque toutes les lignes correspondant ENDou le début de file ( \%^). Ensuite, il procède à tout supprimer des lignes marquées jusqu'à STARTla fin de file ( \%$) ou à la fin en utilisant la commande de substitution s/.*//.

Un exemple côte à côte:

Before           |After
________________________________
test             |
START            |
this is a test   |this is a test
with multiple    |with multiple
line             |line
END              |
0                |
START            |
0101             |0101
END              |
11               |
111              |

Si vous ne voulez pas de lignes vides, vous pouvez les remplacer s/.*//par ddans la commande globale.

3 D.BenKnoble Sep 10 2020 at 06:31

Juste pour le plaisir, souviens-toi que tu peux toujours faire

:%!sed '/start/\!d;s//&\n/;s/.*\n//;:a;/end/bb;$\!{n;ba};:b;s//\n&/;P;D'

Et c'est toujours «vim»: P