Groupe d'appariement imbriqué dans l'expression régulière

8

J'ai un cas d'utilisation commun lorsque je transforme une expression python de la manière suivante:

value 1
value 2
value 3

dans

['value 1', 'value 2', 'value 3']

La façon la plus simple peut être d'utiliser un mappage, mais je voulais utiliser une substitution pour cette tâche.

Jusqu'à présent, j'ai eu:

s/\(.*\n\)\+/[&]/g

Ce qui se traduit par

[value 1
value 2
value 3
]

Cela soulève une question, car je veux pouvoir faire correspondre le \(.*\), mais pas le \net utiliser le résultat du matched dans un '...'.

Sais-tu comment faire cela?

nobe4
la source
2
Je ne sais pas comment le faire en une seule substitution, mais vous pouvez le faire en 2 en mode visuel (après avoir sélectionné l'expression python): :'<,'>s/\v(.*)\n/'\1', / | s/\v(.*), /[\1]/vous pouvez transformer cela en un mappage visuel: xnoremap ,x :s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>et peut-être en un mappage normal si le expression est à l'intérieur d'un paragraphe: nnoremap ,x :'{+1,'}-1s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>Voici le mappage ,x.
user9433424
1
ne pouvait pas faire avec regex, mais en utilisant des commandes externes:%! echo "[$(sed "s/.*/'&',/" % | tr '\n' ' ' | sed 's/, $//')]"
Sundeep

Réponses:

5

Éditer

Il est possible de le faire en une seule expression si nous utilisons une "expression de remplacement secondaire". Voir en bas pour plus d'informations à ce sujet.

/Éditer

Le problème ici est que vous voulez faire deux choses différentes.

  1. Opérer sur le match dans son ensemble (c'est-à-dire l'entourer de [])

  2. Opérer sur chaque élément du match (c'est-à-dire les entourer de '',)

Vous pouvez facilement faire l'un ou l'autre:

  1. :s/\(.\+\n\)\+/[&]/
  2. :%s/\(.\+\)\n/'\1', /

mais pour autant que je sache, il n'y a aucun moyen de faire les deux en une seule opération. J'ai essayé d'obtenir la sortie appropriée avec quelque chose comme:

:s/\(\(.\+\)\n\)\+/[\2]/

Mais bien sûr, le problème avec cela est que la \2correspondance ne correspond qu'à la dernière correspondance du deuxième ensemble de parenthèses mémoire \(\)et ne se "souvient" de rien avant cela. Vous vous retrouvez donc avec seulement la dernière ligne.

Je recommanderais de faire un pré / post-traitement avec une :s///commande supplémentaire pour se débarrasser des nouvelles lignes avant / après le fait. Voici ce que j'ai trouvé

function! FormatExpression()
   .,/\n^$/s/\(.*\)\n/'\1', /
   s/\(.*\), /[\1]/
endfunction

1ère ligne (Supprimer les nouvelles lignes)

  • .,/\n^$/Il s'agit d'un modificateur de plage pour la recherche et le remplacement. Sans cela, la commande continuera à mutiler votre fichier entier. Actuellement, il passe de la ligne actuelle .à la ligne vierge suivante \n^$. Je ne sais pas comment vous aviez l'intention de diviser les choses, mais vous avez besoin d'un moyen de lui dire d'arrêter.
  • s/ Le début d'une commande de recherche et remplacement
  • \(.*\)\n Faites correspondre la ligne entière, mais enregistrez uniquement la partie sans la nouvelle ligne.
  • '\1', Remplacez la ligne par la correspondance entourée de guillemets simples et ajoutez une virgule.

2e ligne (Surround entre parenthèses)

  • \(.*\), Correspond à la ligne entière mais pas à la dernière virgule et espace
  • [\1] Entourez de crochets et supprimez également la virgule de fin superflue et l'espace.

Je vais continuer à chercher, mais pour le moment je ne pense pas que ce soit possible avec une seule expression. :(

ÉDITER:

J'ai trouvé un moyen de le faire avec une seule expression! En interne, il s'agit en fait de deux substitutions, mais il s'agit techniquement d'une seule expression. Voici ce que j'ai trouvé:

:s/\v((.+\n)*.+)\n/\= "['" . substitute(submatch(1), '\n', "', '", 'g') . "']" /
  • :s///: Faites une substitution
  • \v((.+\n)*.+)\n: Rassemble essentiellement toutes les lignes non vides suivantes et les stocke toutes sauf la finale \n
  • \=Permet d'utiliser une expression dans le remplacement (voir :h sub-replace-expression)
  • substitute(submatch(1)...): Remplace tous ceux stockés \npar', '
  • "['" . ... . "']": Ajoute ['et ajoute']

Cela commencera à la position du curseur et ira jusqu'à ce qu'il trouve une ligne vierge ( ^\n). Ne pas saisir le dernier \nest important car sans ce bit, nous nous retrouvons avec un autre ',que nous ne voulons pas à la fin.

Certains pourraient considérer cela comme plus complexe que la réponse à deux expressions précédente. Mais j'ai pensé que j'irais de l'avant et ajouterais cela car il est en fait possible de le faire avec une seule expression. :)

Tumbler41
la source
2

Surlignez visuellement, puis:

:'<,'> s/.*/['&']/ | *j! | s/]\[/, /ge

Il entoure chaque ligne, pour faire par exemple ['value 1'], les joint toutes, puis remplace les espaces adjacents ]et [par des virgules.

La documentation de *in *j!est à :help cpo-starpropos. Celui-là est un peu difficile à trouver.

Antony
la source
Beau travail autour :)
nobe4
En fait, vous pouvez utiliser :'<,'>s/\v(.*)(\_.)/['\1']/et supprimer la jointure.
nobe4
Oui, mais ça mange la finale \n, c'est pourquoi j'ai utilisé :join. J'aurais probablement dû le mentionner. :-)
Antony
1
Et '<,'>s/.*/['&']/ | *s/]\_.\[/, /alors?
nobe4
1
Ouais, c'est mieux. Bien que j'écrirais probablement la deuxième partie comme *s/]\n\[/, /e.
Antony