Gruppo di corrispondenza nidificato in regex


8

Ho un caso d'uso comune quando trasformo alcune espressioni python nel modo seguente:

value 1
value 2
value 3

in

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

Il modo più semplice potrebbe essere quello di utilizzare una mappatura, ma volevo usare una sostituzione per questo compito.

Finora ho ottenuto:

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

Quale risultato in

[value 1
value 2
value 3
]

Questo solleva una domanda, perché voglio essere in grado di abbinare il \(.*\), ma non il \ne l'uso del risultato della corrispondenza all'interno di a '...'.

Sai come si fa?


2
Non so come farlo in una singola sostituzione, ma potresti farlo in 2 mentre sei in modalità visiva (dopo aver selezionato l'espressione python): :'<,'>s/\v(.*)\n/'\1', / | s/\v(.*), /[\1]/potresti trasformarlo in un mapping visivo: xnoremap ,x :s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>e forse in un normale mapping se il L'espressione è all'interno di un paragrafo: nnoremap ,x :'{+1,'}-1s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>qui la mappatura sarebbe ,x.
user9433424,

1
non si poteva fare con regex, ma usando comandi esterni:%! echo "[$(sed "s/.*/'&',/" % | tr '\n' ' ' | sed 's/, $//')]"
Sundeep

Risposte:


5

modificare

È possibile farlo in una sola espressione se utilizziamo una "sub-sostituzione-espressione". Vedi in basso per informazioni al riguardo.

/Modificare

Il problema qui è che vuoi fare due cose diverse.

  1. Operare sull'intera partita (cioè circondarla di [])

  2. Operare su ciascun elemento della partita (ad esempio circondandoli con '',)

Puoi facilmente fare uno dei due:

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

ma per quanto ne so non c'è modo di fare entrambi in un'unica operazione. Ho provato a ottenere l'output corretto con qualcosa del tipo:

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

Ma ovviamente il problema è che \2corrisponde solo all'ultima partita della seconda serie di parentesi di memoria \(\)e non "ricorda" nulla prima. Quindi finisci con solo l'ultima riga.

Consiglierei di eseguire un po 'di pre / post elaborazione con un :s///comando aggiuntivo per sbarazzarsi delle nuove righe prima / dopo il fatto. Ecco cosa mi è venuto in mente

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

1a riga (Rimuovi nuove righe)

  • .,/\n^$/Questo è un modificatore di intervallo per la ricerca e la sostituzione. Senza questo, il comando continuerà a mutilare l'intero file. Attualmente passa dalla riga corrente .alla successiva riga vuota \n^$. Non sono sicuro di come avresti voluto dividere le cose, ma hai bisogno di un modo per dirle di smettere.
  • s/ L'inizio di un comando di ricerca e sostituzione
  • \(.*\)\n Abbina l'intera riga, ma salva solo la parte senza la nuova riga.
  • '\1', Sostituisci la riga con la corrispondenza racchiusa tra virgolette singole e aggiungi una virgola.

2a riga (Surround tra parentesi)

  • \(.*\), Abbina l'intera riga ma non l'ultima virgola e lo spazio
  • [\1] Circonda tra parentesi e rimuovi anche la virgola finale superflua e lo spazio.

Continuerò a esaminarlo, ma al momento non penso che sia possibile con una sola espressione. :(

MODIFICARE:

Ho trovato il modo di farlo con una sola espressione! Internamente si tratta in realtà di due sostituzioni, ma tecnicamente è un'espressione. Ecco cosa mi è venuto in mente:

:s/\v((.+\n)*.+)\n/\= "['" . substitute(submatch(1), '\n', "', '", 'g') . "']" /
  • :s///: Effettua una sostituzione
  • \v((.+\n)*.+)\n: Fondamentalmente raccoglie tutte le successive righe non vuote e le memorizza tutte tranne la finale \n
  • \=Ci permette di usare un'espressione nella sostituzione (vedi :h sub-replace-expression)
  • substitute(submatch(1)...): Sostituisce tutti i file memorizzati \ncon', '
  • "['" . ... . "']": Antepone ['e aggiunge']

Questo inizierà dalla posizione del cursore e proseguirà fino a quando non troverà una linea vuota ( ^\n). Non afferrare l'ultimo \nè importante perché senza quel poco ci rimane un ulteriore ',che non vogliamo alla fine.

Alcuni potrebbero considerarlo più complesso della precedente risposta a due espressioni. Ma ho pensato di andare avanti e aggiungere questo dato che in effetti è possibile farlo con una sola espressione. :)


2

Evidenzia visivamente, quindi:

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

Circonda ogni linea, per esempio ['value 1'], le unisce tutte, quindi sostituisce adiacente ]e [con spazio-virgola.

A proposito, la documentazione per *in *j!è :help cpo-star. È un po 'difficile da trovare.


Bel lavoro in giro :)
nobe4

In realtà è possibile utilizzare :'<,'>s/\v(.*)(\_.)/['\1']/e rimuovere il collegamento.
nobe4,

Sì, ma mangia la finale \n, ecco perché l'ho usato :join. Probabilmente avrei dovuto dirlo. :-)
Antony,

1
E '<,'>s/.*/['&']/ | *s/]\_.\[/, /allora?
nobe4,

1
Sì, va meglio. Anche se probabilmente scriverei la seconda parte come *s/]\n\[/, /e.
Antony,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.