2012-05-09 25 views
16

Ho una lista di circa 120 mila parole inglesi (in pratica ogni parola nella lingua).Corrispondenza con caratteri jolly espressione regolare

Ho bisogno di un'espressione regolare che consenta la ricerca attraverso queste parole utilizzando caratteri jolly, a.k.a. * e ?.

Alcuni esempi:

  • se l'utente cerca m?st*, sarebbe partita per esempio master o mister o mistery.
  • se l'utente cerca *ind (ogni parola che termina in ind), sarebbe partita wind o bind o blind o grind.

Ora, la maggior parte degli utenti (soprattutto quelli che non hanno familiarità con le espressioni regolari) sanno che ? è un sostituto per esattamente 1 carattere, mentre * è un sostituto per 0, 1 o più caratteri. Voglio assolutamente creare la mia funzione di ricerca basata su questo.

Le mie domande sono: Come posso convertire ciò che l'utente digita (m?st* ad esempio) in un'espressione regolare?

Ho cercato sul web (ovviamente includendo questo sito) e tutto quello che ho potuto trovare erano tutorial che cercavano di insegnarmi troppo o domande che erano in qualche modo simili, ma non abbastanza da fornire una risposta al mio problema.

Tutto quello che riuscivo a capire era che devo sostituire ? con .. Quindi m?st* diventa m.st*. Tuttavia, non ho idea di cosa sostituire * con.

Qualsiasi aiuto sarebbe molto apprezzato. Grazie.

PS: Sono assolutamente nuovo alle espressioni regolari. So quanto possono essere potenti, ma so anche che possono essere molto difficili da imparare. Così ho mai preso il tempo fare per esso ...

+1

possibile duplicato di [Esiste un equivalente di java.util.regex per i modelli di tipo "glob"?] (Http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java- util-regex-for-glob-type-patterns) – NPE

+2

Ricorda che tutti i caratteri * altri * regex che potrebbero apparire nella tua query dovranno essere anche sottoposti a escape. Se qualcuno digita '^ \ w..' probabilmente non vuoi passarlo al tuo motore di espressioni regolari nella sua forma originale – Gareth

+0

@Gareth Grazie, lo ricorderò. –

risposta

15

A meno che non si desidera un comportamento divertente, mi sento di raccomandare di utilizzare \w invece di .

. partite simboli non-parola spazi bianchi e gli altri, che non si potrebbe desiderare di fare.

Quindi mi sento di sostituire ? con \w e sostituirlo con *\w*

Anche se si desidera * per abbinare almeno un carattere, sostituirlo con \w+ invece. Ciò significherebbe che ben* corrisponderebbe a bend e bending ma non a ben - dipende da te, dipende solo dalle tue esigenze.

+0

La domanda dice "mentre' * 'è una sostituzione di 0, 1 o più caratteri" – Gareth

+2

@Gareth ya, l'ho visto. Ho pensato di offrire le informazioni extra. – gnomed

+0

@gnomed Perché '\ w' meglio di' .'? –

1

. è un'espressione che corrisponde uno qualsiasi carattere, come hai scoperto. Nelle tue ore di ricerca, hai indubbiamente imbattuto anche in *, che è un operatore di ripetizione che quando viene utilizzato dopo un'espressione corrisponde a l'espressione precedente zero o più volte in una riga.

Quindi l'equivalente del tuo significato di * sta mettendo insieme questi due elementi: .*. Questo significa quindi "qualsiasi carattere zero o più volte".

Vedere Regex Tutorial on repetition operators.

+0

Sì, lo so, non sono così bravo a trovare cose sul web, soprattutto se sono totalmente estraneo a loro :). –

1

Sostituire * con .* (l'espressione regolare di "0 o più di qualsiasi carattere").

6

Sostituire ? con . e * con .*.

2
  1. Sostituisci tutto "?" personaggi con '\ w'
  2. sostituire tutti i '*' caratteri con '\ w *'

L'operatore '*' ripete la voce precedente '' (qualsiasi carattere) 0 o più volte.

Ciò presuppone che nessuna delle parole contenga ".", "*" E "?".

Questo è un buon riferimento

http://www.regular-expressions.info/reference.html

0
function matchWild(wild,name) 
{ 
    if (wild == '*') return true; 

    wild = wild.replace(/\./g,'\\.'); 
    wild = wild.replace(/\?/g,'.'); 
    wild = wild.replace(/\\/g,'\\\\'); 
    wild = wild.replace(/\//g,'\\/'); 
    wild = wild.replace(/\*/g,'(.+?)'); 

    var re = new RegExp(wild,'i'); 
    return re.test(name); 
} 
2

Ecco un modo per trasformare jolly in regex:

  1. Prepend tutti special characters([{\^- = $! |]}). + con \ - quindi sono abbinati come caratteri e non rendono l'esperienza utente inaspettata. Inoltre, è possibile includerlo entro \ Q (che inizia la citazione) e \ E (che termina). Vedi anche paragrafo sulla sicurezza.
  2. Sostituisci * carattere jolly con \ S *
  3. Sostituire? carattere jolly con \ S?
  4. Opzionalmente: modello anteposto con ^ - questo imporrà la corrispondenza esatta con l'inizio.
  5. Opzionalmente: aggiungi $ al modello - questo imporrà la corrispondenza esatta con la fine.

    \ S - sta per carattere non spaziale, che si verifica zero o più volte.

Considerate using reluctant (non-greedy) quantifiers se si dispone di caratteri da dopo * o +. Questo può essere fatto aggiungendo ? dopo * o + come questo: \ S *? e \ S * +?

consideri sicurezza: utente ti invierà il codice per eseguire (perché regex è una specie di codice di troppo, e la stringa utente viene utilizzato come l'espressione regolare). Evitare di passare espressioni regolari senza escape a qualsiasi altra parte dell'applicazione e utilizzare solo per filtrare i dati recuperati con altri mezzi. Perché se lo fai l'utente può influenzare la velocità del tuo codice fornendo diverse regex con stringa jolly - questo potrebbe essere usato negli attacchi DoS.

esempio per mostrare velocità di esecuzione degli schemi simili:

seq 1 50000000 > ~/1 
du -sh ~/1 
563M 
time grep -P '.*' ~/1 &>/dev/null 
6.65s 
time grep -P '.*.*.*.*.*.*.*.*' ~/1 &>/dev/null 
12.55s 
time grep -P '.*..*..*..*..*.*' ~/1 &>/dev/null 
31.14s 
time grep -P '\S*.\S*.\S*.\S*.\S*\S*' ~/1 &>/dev/null 
31.27s 

Io suggerirei contro l'uso * semplicemente perché può abbinare qualsiasi cosa, e di solito le cose sono separati da spazi..

0

Questo è quello che uso:

String wildcardToRegex(String wildcardString) { 
    // The 12 is arbitrary, you may adjust it to fit your needs depending 
    // on how many special characters you expect in a single pattern. 
    StringBuilder sb = new StringBuilder(wildcardString.length() + 12); 
    sb.append('^'); 
    for (int i = 0; i < wildcardString.length(); ++i) { 
     char c = wildcardString.charAt(i); 
     if (c == '*') { 
      sb.append(".*"); 
     } else if (c == '?') { 
      sb.append('.'); 
     } else if ("\\.[]{}()+-^$|".indexOf(c) >= 0) { 
      sb.append('\\'); 
      sb.append(c); 
     } else { 
      sb.append(c); 
     } 
    } 
    sb.append('$'); 
    return sb.toString(); 
} 

elenco speciale carattere da https://stackoverflow.com/a/26228852/1808989.

Problemi correlati