Hans, abbatterò l'esca e rimpolperò la mia risposta precedente. Hai detto che volevi "qualcosa di più completo", quindi spero che non ti dispiaccia la risposta lunga, cercando solo di accontentare. Cominciamo con un po 'di background.
Prima di tutto, questa è un'ottima domanda. Ci sono spesso domande sulla corrispondenza di determinati modelli tranne che in determinati contesti (ad esempio, all'interno di un blocco di codice o tra parentesi). Queste domande spesso danno luogo a soluzioni piuttosto scomode. Quindi la tua domanda su più contesti è una sfida speciale.
Sorpresa
Sorprendentemente, esiste almeno una soluzione efficiente che è generale, facile da implementare e piacevole da mantenere. Esso funziona con tutti i sapori regex che consentono di ispezionare i gruppi di cattura nel codice. E capita di rispondere a una serie di domande comuni che a prima vista possono sembrare diverse dalle tue: "abbina tutto tranne Donuts", "sostituisci tutto tranne ...", "trova tutte le parole tranne quelle sulla lista nera di mia madre", "ignora tag "," corrisponde alla temperatura a meno che non sia in corsivo "...
Purtroppo, la tecnica non è ben nota: stimo che in venti domande SO che potrebbero usarla, solo una ha una risposta che la menziona, il che significa forse una su cinquanta o sessanta risposte. Vedi il mio scambio con Kobi nei commenti. La tecnica è descritta in modo approfondito in questo articolo che la definisce (ottimisticamente) il "miglior trucco regex di sempre". Senza entrare nei dettagli, cercherò di darti una solida comprensione di come funziona la tecnica. Per maggiori dettagli ed esempi di codice in varie lingue ti incoraggio a consultare quella risorsa.
Una variante meglio conosciuta
Esiste una variazione che utilizza la sintassi specifica di Perl e PHP che realizza lo stesso. Lo vedrai su SO nelle mani di maestri di regex come CasimiretHippolyte e HamZa . Ti dirò di più su questo di seguito, ma il mio focus qui è sulla soluzione generale che funziona con tutti i gusti di regex (purché tu possa ispezionare i gruppi di acquisizione nel tuo codice).
Grazie per tutto il background, zx81 ... Ma qual è la ricetta?
Fatto fondamentale
Il metodo restituisce la corrispondenza nell'acquisizione del gruppo 1. Non si cura affatto della partita generale.
In effetti, il trucco sta nel far corrispondere i vari contesti che non vogliamo (concatenando questi contesti utilizzando l' |alternanza OR /) in modo da "neutralizzarli". Dopo aver abbinato tutti i contesti indesiderate, la parte finale del alternanza corrisponde a quello che facciamo vogliamo e lo cattura al gruppo 1.
La ricetta generale è
Not_this_context|Not_this_either|StayAway|(WhatYouWant)
Questa corrisponderà Not_this_context, ma in un certo senso quella partita finisce in un cestino della spazzatura, perché non guarderemo le partite complessive: guardiamo solo le acquisizioni del Gruppo 1.
Nel tuo caso, ignorando le tue cifre e i tuoi tre contesti, possiamo fare:
s1|s2|s3|(\b\d+\b)
Tieni presente che poiché in realtà abbiniamo s1, s2 e s3 invece di cercare di evitarli con i lookaround, le singole espressioni per s1, s2 e s3 possono rimanere chiare come il giorno. (Sono le sottoespressioni su ogni lato di a |)
L'intera espressione può essere scritta in questo modo:
(?m)^.*\.$|\([^\)]*\)|if\(.*?//endif|(\b\d+\b)
Guarda questa demo (ma concentrati sui gruppi di acquisizione nel riquadro in basso a destra.)
Se provi mentalmente a dividere questa regex in ogni |delimitatore, in realtà è solo una serie di quattro espressioni molto semplici.
Per i gusti che supportano la spaziatura libera, questo si legge particolarmente bene.
(?mx)
### s1: Match line that ends with a period ###
^.*\.$
| ### OR s2: Match anything between parentheses ###
\([^\)]*\)
| ### OR s3: Match any if(...//endif block ###
if\(.*?//endif
| ### OR capture digits to Group 1 ###
(\b\d+\b)
Questo è eccezionalmente facile da leggere e mantenere.
Estensione della regex
Quando vuoi ignorare più situazioni s4 e s5, le aggiungi in più alternanze a sinistra:
s4|s5|s1|s2|s3|(\b\d+\b)
Come funziona?
I contesti che non vuoi vengono aggiunti a un elenco di alternanze sulla sinistra: corrisponderanno, ma queste corrispondenze complessive non vengono mai esaminate, quindi abbinarle è un modo per metterle in un "cestino della spazzatura".
Il contenuto desiderato, tuttavia, viene acquisito nel gruppo 1. È quindi necessario verificare a livello di programmazione che il gruppo 1 sia impostato e non vuoto. Questo è un compito di programmazione banale (e parleremo più avanti di come è fatto), soprattutto considerando che ti lascia con una semplice regex che puoi capire a colpo d'occhio e rivedere o estendere secondo necessità.
Non sono sempre un fan delle visualizzazioni, ma questa fa un buon lavoro nel mostrare quanto sia semplice il metodo. Ogni "linea" corrisponde a una potenziale corrispondenza, ma solo la linea di fondo viene catturata nel Gruppo 1.

Debuggex Demo
Variazione Perl / PCRE
In contrasto con la soluzione generale sopra, esiste una variazione per Perl e PCRE che è spesso vista su SO, almeno nelle mani di regex Gods come @CasimiretHippolyte e @HamZa. È:
(?:s1|s2|s3)(*SKIP)(*F)|whatYouWant
Nel tuo caso:
(?m)(?:^.*\.$|\([^()]*\)|if\(.*?//endif)(*SKIP)(*F)|\b\d+\b
Questa variazione è un po 'più facile da usare perché il contenuto corrispondente nei contesti s1, s2 e s3 viene semplicemente ignorato, quindi non è necessario ispezionare le acquisizioni del gruppo 1 (notare che le parentesi sono sparite). Le partite contengono solowhatYouWant
Notalo (*F), (*FAIL)e (?!)sono tutti la stessa cosa. Se volevi essere più oscuro, potresti usare(*SKIP)(?!)
demo per questa versione
applicazioni
Ecco alcuni problemi comuni che questa tecnica può spesso risolvere facilmente. Noterai che la parola scelta può far suonare alcuni di questi problemi in modo diverso mentre in realtà sono praticamente identici.
- Come posso abbinare foo tranne che ovunque in un tag come
<a stuff...>...</a>?
- Come posso abbinare foo tranne che in un
<i>tag o in uno snippet javascript (più condizioni)?
- Come posso abbinare tutte le parole che non sono in questa lista nera?
- Come posso ignorare qualsiasi cosa all'interno di un blocco SUB ... END SUB?
- Come posso abbinare tutto tranne ... s1 s2 s3?
Come programmare le acquisizioni del gruppo 1
Non hai fatto come per il codice, ma, per il completamento ... Il codice per ispezionare il Gruppo 1 dipenderà ovviamente dalla tua lingua scelta. In ogni caso, non dovrebbe aggiungere più di un paio di righe al codice che useresti per controllare le corrispondenze.
In caso di dubbio, ti consiglio di consultare la sezione degli esempi di codice dell'articolo citato in precedenza, che presenta il codice per un bel po 'di lingue.
alternative
A seconda della complessità della domanda e del motore di regex utilizzato, ci sono diverse alternative. Ecco i due che possono essere applicati alla maggior parte delle situazioni, comprese più condizioni. A mio avviso, nessuno dei due è attraente come la s1|s2|s3|(whatYouWant)ricetta, se non altro perché la chiarezza vince sempre.
1. Sostituisci quindi Abbina.
Una buona soluzione che suona hacky ma funziona bene in molti ambienti è lavorare in due passaggi. Una prima regex neutralizza il contesto che vuoi ignorare sostituendo stringhe potenzialmente in conflitto. Se desideri solo la corrispondenza, puoi sostituirla con una stringa vuota, quindi eseguire la corrispondenza nel secondo passaggio. Se vuoi sostituire, puoi prima sostituire le stringhe da ignorare con qualcosa di distintivo, ad esempio circondando le tue cifre con una catena a larghezza fissa di @@@. Dopo questa sostituzione, sei libero di sostituire ciò che volevi veramente, quindi dovrai ripristinare le tue @@@corde distintive .
2. Lookaround.
Il tuo post originale mostrava che comprendi come escludere una singola condizione utilizzando i lookaround. Hai detto che C # è ottimo per questo e hai ragione, ma non è l'unica opzione. Le versioni regex .NET trovate in C #, VB.NET e Visual C ++, ad esempio, così come il regexmodulo ancora sperimentale da sostituire rein Python, sono gli unici due motori che conosco che supportano il lookbehind a larghezza infinita. Con questi strumenti, una condizione in uno sguardo dietro può occuparsi di guardare non solo dietro ma anche sulla partita e oltre la partita, evitando la necessità di coordinarsi con uno sguardo in avanti. Altre condizioni? Altri lookaround.
Riciclando la regex che avevi per s3 in C #, l'intero modello sarebbe simile a questo.
(?!.*\.)(?<!\([^()]*(?=\d+[^)]*\)))(?<!if\(\D*(?=\d+.*?//endif))\b\d+\b
Ma ormai sai che non lo sto raccomandando, giusto?
eliminazioni
@HamZa e @Jerry hanno suggerito di menzionare un trucco aggiuntivo per i casi in cui si cerca di eliminare WhatYouWant. Ricordi che la ricetta da abbinare WhatYouWant(catturandola nel Gruppo 1) era s1|s2|s3|(WhatYouWant), giusto? Per eliminare tutte le istanze di WhatYouWant, cambia la regex in
(s1|s2|s3)|WhatYouWant
Per la stringa sostitutiva, usi $1. Quello che succede qui è che per ogni istanza di s1|s2|s3quello è abbinato, la sostituzione $1sostituisce quell'istanza con se stessa (a cui fa riferimento $1). D'altra parte, quando WhatYouWantviene abbinato, viene sostituito da un gruppo vuoto e nient'altro - e quindi eliminato. Guarda questa demo , grazie @HamZa e @Jerry per aver suggerito questa fantastica aggiunta.
sostituzioni
Questo ci porta alle sostituzioni, sulle quali toccherò brevemente.
- Quando si sostituisce con niente, vedere il trucco "Eliminazioni" sopra.
- Quando si sostituisce, se si utilizza Perl o PCRE, utilizzare la
(*SKIP)(*F)variante menzionata sopra per corrispondere esattamente a ciò che si desidera ed eseguire una sostituzione diretta.
- In altri gusti, all'interno della chiamata alla funzione di sostituzione, ispeziona la corrispondenza utilizzando un callback o lambda e sostituisci se è impostato il gruppo 1. Se hai bisogno di aiuto con questo, l'articolo già citato ti fornirà il codice in varie lingue.
Divertiti!
No, aspetta, c'è di più!
Ah, nah, lo terrò per le mie memorie in venti volumi, in uscita la prossima primavera.
\Knon è una sintassi php speciale. Si prega di elaborare e chiarire ciò che si vuole dire. Se vuoi dirci che non hai bisogno di una soluzione "complicata" devi dire cosa è complicato per te e perché.