2013-02-26 6 views
5

ho bisogno di filtrare una raccolta di stringhe basato su una query piuttosto complesso - nella sua "prima" forma che assomiglia a questo:Javascript regex pattern match più stringhe (AND, OR) contro singola stringa

nano* AND (regulat* OR *toxic* OR ((risk OR hazard) AND (exposure OR release))) 

un esempio di una delle stringhe per abbinare contro:

Workshop on the Second Regulatory Review on Nanomaterials, 30 January 2013, Brussels 

così, ho bisogno di abbinare utilizzando AND OR e caratteri jolly - così, suppongo che avrò bisogno di usare una regex in JavaScript.

Ho tutto in loop in modo corretto, il filtraggio e in genere di lavoro, ma sono sicuro al 100% il mio regex è sbagliato - e alcuni risultati sono stati omessi a torto - qui è:

/(nano[a-zA-Z])?(regulat[a-zA-Z]|[a-zA-Z]toxic[a-zA-Z]|((risk|hazard)*(exposure|release)))/i 

Qualsiasi aiuto sarebbe essere molto apprezzato - non posso davvero astrarre la mia mente correttamente per capire questa sintassi!

UPDATE:

Poche persone sono sottolineare l'importanza del l'ordine in cui si costruisce la regex, ma non ho alcun controllo sulle stringhe di testo che verrà effettuata la ricerca, quindi ho bisogno di trovare una soluzione che possa funziona indipendentemente dall'ordine o da entrambi.

UPDATE:

Alla fine utilizzata una soluzione PHP, a causa della disapprovazione di Twitter API 1.0, vedere pastebin per esempio di funzione (lo so che è meglio per incollare il codice qui, ma non c'è un sacco ...):

funzione: http://pastebin.com/MpWSGtHK utilizzo: http://pastebin.com/pP2AHEvk

Grazie per tutto l'aiuto

+0

Si potrebbe desiderare di provare [un live strumento di test RegExp] (http://www.gethifi.com/tools/regex). – Barney

+0

Nella stringa di esempio, 'nano' viene dopo 'normativa', ma nella tua espressione regolare, è il contrario. C'è qualche schema atteso in questo modo che uno verrà sempre prima dell'altro? Alcuni altri esempi potrebbero aiutare a spiegare le vostre esigenze. –

+0

@Barney - un buon consiglio, ecco come sono arrivato a questo punto –

risposta

19

Una singola espressione regolare non è lo strumento giusto per questo, IMO:.

/^(?=.*\bnano)(?=(?:.*\bregulat|.*toxic|(?=.*(?:\brisk\b|\bhazard\b))(?=.*(?:\bexposure\b|\brelease\b))))/i.test(subject)) 

sarebbe restituirà true se la stringa soddisfa i criteri enunciati, ma io trova lookheadhead innestati abbastanza incomprensibile. Se supportato commentato espressioni regolari JavaScript, sarebbe simile a questa:

^     # Anchor search to start of string 
(?=.*\bnano)  # Assert that the string contains a word that starts with nano 
(?=    # AND assert that the string contains... 
(?:    # either 
    .*\bregulat  # a word starting with regulat 
|    # OR 
    .*toxic   # any word containing toxic 
|    # OR 
    (?=    # assert that the string contains 
    .*    # any string 
    (?:   # followed by 
    \brisk\b  # the word risk 
    |    # OR 
    \bhazard\b # the word hazard 
    )    # (end of inner OR alternation) 
)    # (end of first AND condition) 
    (?=    # AND assert that the string contains 
    .*    # any string 
    (?:   # followed by 
    \bexposure\b # the word exposure 
    |    # OR 
    \brelease\b # the word release 
    )    # (end of inner OR alternation) 
)    # (end of second AND condition) 
)    # (end of outer OR alternation) 
)     # (end of lookahead assertion) 

Si noti che l'intera espressione regolare è composto da asserzioni guardano avanti, in modo che il risultato della partita in sé sarà sempre una stringa vuota.

Invece, è possibile utilizzare singoli regex:

if (/\bnano/i.test(str) && 
    ( 
     /\bregulat|toxic/i.test(str) || 
     ( 
      /\b(?:risk|hazard)\b/i.test(str) && 
      /\b(?:exposure|release)\b/i.test(str) 
     ) 
    ) 
) /* all tests pass */ 
+0

molto bello - provalo ora .. grazie! –

+0

per favore potresti spiegare [\ b] - ho letto che "\ b è un carattere backspace" ma non sono sicuro di come sia rilevante? –

+0

@QLStudio: in una stringa normale, '" \ b "' è davvero un backspace In una regex, '/ \ b /' (equivalente a 'new Regex (" \\ b ")') è un [ancoraggio al contorno di parola] (http://www.regular-expressions.info/wordboundaries.html Questo ancoraggio corrisponde all'inizio o alla fine di una parola alfanumerica, quindi '/ \ brisk \ b /' corrisponde solo a '" risk "' or' "C'è un rischio! "', ma non '" vivace "' o '" rischioso "'. –

2

espressioni regolari devono muoversi attraverso la stringa in ordine. Hai "nano" prima di "regulat" nel pattern, ma vengono scambiati nella stringa di test. Invece di usare regexen per fare questo, mi piacerebbe restare con Plain Old parsing della stringa:

if (str.indexOf('nano') > -1) { 
    if (str.indexOf('regulat') > -1 || str.indexOf('toxic') > -1 
     || ((str.indexOf('risk') > - 1 || str.indexOf('hazard') > -1) 
     && (str.indexOf('exposure') > -1 || str.indexOf('release') > -1) 
    )) { 
     /* all tests pass */ 
    } 
} 

Se si desidera catturare in realtà le parole (ad esempio ottenere "regolamentazione" da dove "regulat" è, vorrei dividere il frase di interruzioni di parola e ispezionare le parole singole

+1

@EP - per favore vedi il mio commento sopra, l'ordine della stringa con cui sto confrontando è casuale come il suo contenuto .. sto solo provando "filtrare" su una vasta raccolta di tweet basata sulla regex - forse questo è l'approccio sbagliato? –

+0

@QLStudio è il mio suggerimento inappropriato per questo? –

+0

@EP - sì, mi dispiace - la tua soluzione risolve il problema dell'ordine .. ma posso ancora usare caratteri jolly (*) in una normale ricerca JS? –