Pliage par motif de recherche regex

13

J'ai obtenu un fichier texte brut avec des colonnes de valeurs séparées par des espaces. Comme ça:

AU 3030 .... ... ....  
AU 3031 .... ... ....  
AU 3032 .... ... .... 
AU 3033 .... ... .... 
IT 48100 ... .. .....
IT 40100 ... .. .....
IT 48123 ... .. .....
UK 3333 ... ... ..... 
UK 4444 ... ... .....
UK 5555 ... ... .....

J'ai également obtenu cette expression régulière qui correspondra à toute ligne adjacente avec la même valeur dans la première colonne (supposons que le fichier est trié sur la première colonne), sauf la dernière:

/^\(\([A-Z0-9]\+\)\s\+.*\n\)\(\2\)\@=

(ou pour le rendre moins "velu"):

/^\v([A-Z0-9]+)\s+.*\n(\1)@=

Est-il possible de replier des lignes sur la ligne qui n'a pas été appariée? Ayant ce résultat:

+-- 4 lines AU ....
+-- 3 lines IT ....
+-- 3 lines UK ....
guido
la source

Réponses:

14

Faites set foldmethod=expret utilisez 'foldexpr'pour définir une expression de script vim qui définira les points de départ du pli.

set foldmethod=expr
set foldexpr=get(split(getline(v:lnum-1)),0,'')!=get(split(getline(v:lnum)),0,'')?'>1':'='

Cela semble plus compliqué qu'il ne l'est, car nous ne pouvons pas facilement utiliser des espaces dans :set, mais avec des espaces, et une nouvelle ligne ou 2, cela ressemble à:

get(split(getline(v:lnum - 1)), 0, '') != get(split(getline(v:lnum)), 0, '')
    \ ? '>1'
    \ : '='

Aperçu

Fondamentalement, cela compare le premier mot de chaque ligne avec la ligne précédente. Si les mots sont différents, la ligne est début du repli, >1. Sinon , il garde le même niveau de repli, =.

Gloire des détails

  • set foldmethod=expr pour dire à Vim d'utiliser une expression de script vim pour déterminer les plis
  • 'foldexpr' L'option contient l'expression de script vim
  • Évaluation de la condition avec un ternaire qui revient >1quand un pli doit commencer et =quand le niveau de pli doit continuer
  • v:lnumest la ligne actuelle qui 'foldexpr'est en cours d'exécution pour mettre à jour les plis
  • Récupère le contenu de la ligne actuelle ( v:lnum) et de la ligne précédente ( v:lnum - 1) viagetline()
  • Divisez chaque ligne en mots via split()
  • Utilisez get()pour obtenir le premier index des mots fraîchement divisés
  • Utilisez une valeur par défaut de ''dans le cas d'une ligne vide. par exempleget(words, 0, '')
  • Comparer le premier mot de la ligne actuelle avec le premier mot de la ligne précédente dans la partie condition du ternaire

Remarque: cette méthode peut avoir des problèmes de performances avec des documents très volumineux

Pour plus d'aide, voir:

:h 'foldmethod'
:h 'foldexpr'
:h getline(
:h v:lnum
:h split(
:h get(
Peter Rincker
la source