2011-02-07 15 views
7

Sto facendo un po 'di ginnastica di espressione regolare. Mi sono posto il compito di provare a cercare il codice C# in cui vi è un utilizzo dell'operatore as non seguito da un controllo null all'interno di una quantità ragionevole di spazio. Ora non voglio analizzare il codice C#. Per esempio. Voglio catturare frammenti di codice comeEspressioni regolari lookahead negativo

var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(x1.a == y1.a) 

tuttavia, non catturare

var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(x1 == null) 

né per quella materia

var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(somethingunrelated == null) {...} 
    if(x1.a == y1.a) 

Pertanto, qualsiasi null-controllo casuale conterà come un "buon controllo "e quindi non trovato.

La domanda è: Come faccio ad abbinare qualcosa assicurando che qualcos'altro non si trova nei suoi dintorni.

Ho provato l'approccio ingenuo, cercando 'come' quindi facendo un lookahead negativo entro 150 caratteri.

\bas\b.{1,150}(?!\b==\s*null\b) 

L'espressione regolare precedente corrisponde a tutti gli esempi precedenti in modo infondato. Il mio istinto mi dice che il problema è che guardando avanti e facendo un lookahead negativo si possono trovare molte situazioni in cui il lookahead non trova il valore '== null'.

Se provo a negare l'intera espressione, anche questo non aiuta, a questo corrisponderebbe la maggior parte del codice C#.

+2

Non è possibile utilizzare un parser C# corretto? – Gumbo

+2

Ho detto all'inizio "Sto facendo un po 'di ginnastica di espressione regolare, mi sono dato il compito di cercare C#" ... –

+0

È come guardare il calcio e pensare "è come fare ginnastica"? :-) – xanatos

risposta

11

I amore ginnastica regex! Qui è un'espressione regolare PHP commentato:

$re = '/# Find all AS, (but not preceding a XX == null). 
    \bas\b    # Match "as" 
    (?=     # But only if... 
     (?:    # there exist from 1-150 
     [\S\s]   # chars, each of which 
     (?!==\s*null) # are NOT preceding "=NULL" 
    ){1,150}?   # (and do this lazily) 
     (?:    # We are done when either 
     (?=    # we have reached 
      ==\s*(?!null) # a non NULL conditional 
     )    # 
     | $    # or the end of string. 
    ) 
    )/ix' 

E qui è in stile Javascript:

re = /\bas\b(?=(?:[\S\s](?!==\s*null)){1,150}?(?:(?===\s*(?!null))|$))/ig; 

Questo ha fatto la mia testa un po 'male ...

qui sono i dati di prova che sto utilizzando:

text = r""" var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(x1.a == y1.a) 

however, not capture 
    var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(x1 == null) 

nor for that matter 
    var x1 = x as SimpleRes; 
    var y1 = y as SimpleRes; 
    if(somethingunrelated == null) {...} 
    if(x1.a == y1.a)""" 
+0

E se si desidera che funzioni con un test condizionale negativo, ad es. 'X! = Null', cambia semplicemente ognuno:' == 'a:' [! =] = ' – ridgerunner

+0

Molto ben fatto e buona spiegazione. +1. Includerei il solito avvertimento sulla regex che non è affidabile al 100% per l'analisi di C#, tuttavia. –

2

Mettere il .{1,150} all'interno del lookahead, e sostituirlo con .\s\S (in generale, . non corrisponde a capo). Inoltre, lo \b potrebbe essere fuorviante vicino allo ==.

\bas\b(?![\s\S]{1,150}==\s*null\b) 
+0

Non riesco a far funzionare la tua idea, include ancora il secondo esempio sopra nei miei risultati di ricerca. –

+0

Questa espressione regolare: '\ bas \ b (?! [\ S \ S] {1.150} == \ s * null \ b)' è abbastanza vicino, ma non corrisponde al secondo AS nel primo set di "deve corrispondere " dati di test. – ridgerunner

+0

@ridgerunner funziona per te con Python? Non ho una configurazione C# per testare con. – robert

2

Penso che sarebbe utile inserire il nome della variabile in() in modo da poterlo usare come riferimento per la parte posteriore. Qualcosa come il seguente,

\b(\w+)\b\W*=\W*\w*\W*\bas\b[\s\S]{1,150}(?!\b\1\b\W*==\W*\bnull\b) 
2

La domanda non è chiara. Cosa vuoi esattamente ? Mi dispiace, ma continuo a non capire, dopo aver letto la domanda e i commenti numerose volte.

.

Il codice deve essere in C#? In Python? Altro ?Non vi sono indicazioni su questo punto

.

Si desidera un abbinamento solo se una riga if(... == ...) segue un blocco di righe var ... = ...?

Oppure una riga eterogenea può essere FRA il blocco e la riga if(... == ...) senza interrompere l'abbinamento?

Il mio codice accetta la seconda opzione come vera.

.

Una linea if(... == null) DOPO una linea if(... == ...) interrompe il collegamento o no?

Impossibile capire se è sì o no, ho definito le due regex per catturare queste due opzioni.

.

Spero che il mio codice sia abbastanza chiaro e che risponda alla tua preoccupazione.

E 'in Python

import re 

ch1 ='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1.a == y1.a) 
1618987987849891 
''' 

ch2 ='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
uydtdrdutdutrr 
if(x1.a == y1.a) 
3213546878''' 

ch3='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1 == null) 
165478964654456454''' 

ch4='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
hgyrtdduihudgug 
if(x1 == null) 
165489746+54646544''' 

ch5='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(somethingunrelated == null) {...} 
if(x1.a == y1.a) 
1354687897''' 

ch6='''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
ifughobviudyhogiuvyhoiuhoiv 
if(somethingunrelated == null) {...} 
if(x1.a == y1.a) 
2468748874897498749874897''' 

ch7 = '''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1.a == y1.a) 
iufxresguygo 
liygcygfuihoiuguyg 
if(somethingunrelated == null) {...} 
oufxsyrtuy 
''' 

ch8 = '''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
tfsezfuytfyfy 
if(x1.a == y1.a) 
iufxresguygo 
liygcygfuihoiuguyg 
if(somethingunrelated == null) {...} 
oufxsyrtuy 
''' 

ch9 = '''kutgdfxfovuyfuuff 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
tfsezfuytfyfy 
if(x1.a == y1.a) 
if(somethingunrelated == null) {...} 
oufxsyrtuy 
''' 

pat1 = re.compile(('(' 
        '(^var +\S+ *= *\S+ +as .+[\r\n]+)+?' 
        '([\s\S](?!==\s*null\\b))*?' 
        '^if *\(*[^\s=]+ *==(?!\s*null).+$' 
        ')' 
        ), 
        re.MULTILINE) 

pat2 = re.compile(('(' 
        '(^var +\S+ *= *\S+ +as .+[\r\n]+)+?' 
        '([\s\S](?!==\s*null\\b))*?' 
        '^if *\(*[^\s=]+ *==(?!\s*null).+$' 
        ')' 
        '(?![\s\S]{0,150}==)' 
        ), 
        re.MULTILINE) 


for ch in (ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9): 
    print pat1.search(ch).group() if pat1.search(ch) else pat1.search(ch) 
    print 
    print pat2.search(ch).group() if pat2.search(ch) else pat2.search(ch) 
    print '-----------------------------------------' 

Risultato

>>> 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1.a == y1.a) 

var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1.a == y1.a) 
----------------------------------------- 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
uydtdrdutdutrr 
if(x1.a == y1.a) 

var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
uydtdrdutdutrr 
if(x1.a == y1.a) 
----------------------------------------- 
None 

None 
----------------------------------------- 
None 

None 
----------------------------------------- 
None 

None 
----------------------------------------- 
None 

None 
----------------------------------------- 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
if(x1.a == y1.a) 

None 
----------------------------------------- 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
tfsezfuytfyfy 
if(x1.a == y1.a) 

None 
----------------------------------------- 
var x1 = x as SimpleRes; 
var y1 = y as SimpleRes; 
tfsezfuytfyfy 
if(x1.a == y1.a) 

None 
----------------------------------------- 
>>> 
+0

+1 Sono d'accordo che la domanda è abbastanza vaga. La maggior parte delle persone non capisce che una buona domanda di regex deve essere spiegata in modo molto preciso. – ridgerunner

2

Vorrei cercare di ridefinire il problema:

  1. cercare un "come" assegnazione - che probabilmente ha bisogno di un è meglio eseguire un'espressione regolare per cercare i compiti effettivi e potrebbe voler memorizzare l'espressione assegnata, ma usiamo "\ bas \ b" per ora
  2. Se vedi un if (... == null) all'interno 150 caratteri, non corrispondono
  3. Se non vedi un if (... == null) all'interno 150 caratteri, partita

tua espressione \bas\b.{1,150}(?!\b==\s*null\b) non funziona a causa del look-negativo avanti. La regex può sempre saltare in avanti o indietro di una lettera per evitare questo look-ahead negativo e si finisce per coincidere anche quando c'è uno if (... == null) lì.

I regex non sono veramente buoni a non corrispondenti a qualcosa. In questo caso, è meglio di cercare di corrispondere a un "come" compito con un "se == null" check entro 150 caratteri:

\bas\b.{1,150}\b==\s*null\b 

e poi negando il controllo: if (!regex.match(text)) ...

1
(?s:\s+as\s+(?!.{0,150}==\s*null\b)) 

Sto attivando l'opzione SingleLine con ?s:. Puoi metterlo nelle opzioni del tuo Regex se vuoi. Aggiungerò che sto inserendo attorno allo as perché penso che solo gli spazi siano "legali" attorno allo as. Probabilmente si può mettere la \b come

(?s:\b+as\b(?!.{0,150}==\s*null\b)) 

essere consapevoli del fatto che \s probabilmente catturare spazi che non sono "spazi validi".È definito come [\f\n\r\t\v\x85\p{Z}] dove \p{Z} è Unicode Characters in the 'Separator, Space' Category più Unicode Characters in the 'Separator, Line' Category più Unicode Characters in the 'Separator, Paragraph' Category.