Come funziona l’espressione regolare ‘(? <= #) + (? = #)'?

Ho il seguente regex in un programma C #, e ho difficoltà a capirlo:

(?<=#)[^#]+(?=#) 

Lo romperò in ciò che penso di aver capito:

 (?<=#) a group, matching a hash. what's `?<=`? [^#]+ one or more non-hashes (used to achieve non-greediness) (?=#) another group, matching a hash. what's the `?=`? 

Quindi il problema che ho è la parte ?<= E ?< . Dalla lettura di MSDN,? ? viene utilizzato per nominare i gruppi, ma in questo caso la parentesi angular non viene mai chiusa.

Non ho trovato ?= Nei documenti, e la ricerca è molto difficile, perché i motori di ricerca ignorano per lo più quei caratteri speciali.

Sono chiamati lookaround; ti permettono di affermare se un modello corrisponde o meno, senza effettivamente fare la partita. Ci sono 4 lookaround di base:

  • Aspetti positivi: vediamo se POSSIAMO abbinare il pattern
    • (?=pattern) – … a destra della posizione corrente (guarda avanti )
    • (?< =pattern) - ... a sinistra della posizione corrente (guarda dietro )
  • Aspetti negativi: vedi se NON possiamo abbinare il pattern
    • (?!pattern) - ... a destra
    • (?< !pattern) - ... a sinistra

Come facile promemoria, per un lookaround:

  • = è positivo ! è negativo
  • < è dietro , altrimenti è guardare avanti

Riferimenti

  • regular-expressions.info/Lookarounds

Ma perché usare lookaround?

Si potrebbe obiettare che i lookaround nel pattern sopra non sono necessari, e #([^#]+)# farà il lavoro bene (estraendo la stringa catturata da \1 per ottenere il non- # ).

Non proprio. La differenza è che dal momento che una soluzione non corrisponde a # , può essere "utilizzata" di nuovo dal prossimo tentativo di trovare una corrispondenza. Semplicisticamente parlando, i lookaround permettono alle "corrispondenze" di sovrapporsi.

Considera la seguente stringa di input:

 and #one# and #two# and #three#four# 

Ora, #([az]+)# darà le seguenti corrispondenze ( come visto su rubular.com ):

 and #one# and #two# and #three#four# \___/ \___/ \_____/ 

Confronta questo con (?< =#)[az]+(?=#) , Che corrisponde a:

 and #one# and #two# and #three#four# \_/ \_/ \___/ \__/ 

Purtroppo questo non può essere dimostrato su rubular.com, dal momento che non supporta il lookbehind. Tuttavia, supporta lookahead, quindi possiamo fare qualcosa di simile con #([az]+)(?=#) , Che corrisponde ( come visto su rubular.com ):

 and #one# and #two# and #three#four# \__/ \__/ \____/\___/ 

Riferimenti

  • regular-expressions.info/Flavor Comparison

Come menzionato da un altro poster, questi sono accorgimenti , costrutti speciali per cambiare ciò che viene abbinato e quando. Questo dice:

 (?< =#) match but don't capture, the string `#` when followed by the next expression [^#]+ one or more characters that are not `#`, and (?=#) match but don't capture, the string `#` when preceded by the last expression 

Quindi questo corrisponderà a tutti i personaggi tra due # s.

Lookaheads e lookbehinds sono molto utili in molti casi. Si consideri, ad esempio, la regola "corrisponde a tutti i b non seguiti da un a ". Il tuo primo tentativo potrebbe essere qualcosa come b[^a] , ma non è giusto: questo corrisponderà anche al bu in bus o al bo in boy , ma tu volevi solo il b . E non corrisponderà al b in cab , anche se non è seguito da un a , perché non ci sono più personaggi da abbinare.

Per farlo correttamente, hai bisogno di un lookahead: b(?!a) . Questo dice "match a b ma non abbinare un a dopo, e non fare quella parte della partita". Quindi abbinerà solo la b in bolo , che è quello che vuoi; allo stesso modo abbinerà il b in cab .