2010-04-16 19 views
6

Vorrei creare un'espressione regolare senza maiuscole e minuscole (per JavaScript) che corrisponda ai nomi delle strade, anche se ogni parola è stata abbreviata. Per esempio:Regex per corrispondere alle parole parziali (JavaScript)

n univ av deve corrispondere N Univ ersity Av e

re BLV deve corrispondere Martin Luther Re Jr. Blv d

ne 9 deve corrispondere a entrambi NE 9th St e St NE

punti bonus (JK) per un'espressione regolare "sostituire" che avvolge il testo abbinato con <b> tag.

+8

Poiché questo è contrassegnato come "divertente", citando Jamie Zawinski: * Alcune persone, quando si trovano di fronte a un problema, pensano "Lo so, userò le espressioni regolari". Ora hanno due problemi. * –

+0

@Pascal: ottima citazione. –

+0

@Andy: Ora devi essere l'unico programmatore * sulla terra * che non ha ancora avuto a che fare con quella particolare citazione. ;) Da parte mia, sono stufo di ciò. oO – Tomalak

risposta

11

avete ottenuto:

"n univ av" 

desiderato:

"\bn.*\buniv.*\bav.*" 

Così si fa:

var regex = new RegExp("n univ av".replace(/(\S+)/g, function(s) { return "\\b" + s + ".*" }).replace(/\s+/g, ''), "gi"); 

Voilà!

Ma non ho finito, voglio i miei punti bonus.Così si cambia il modello da:

var regex = new RegExp("n univ av".replace(/(\S+)/g, function(s) { return "\\b(" + s + ")(.*)" }).replace(/\s+/g, ''), "gi"); 

E poi:

var matches = regex.exec("N University Ave"); 

Ora abbiamo ottenuto:

  • partite [0] => l'intera espressione (inutile)
  • partite [even] => una delle nostre partite
  • partite [dispari] => testo aggiuntivo non sulla stringa originale

Quindi, possiamo scrivere:

var result = ''; 
for (var i=1; i < matches.length; i++) 
{ 
    if (i % 2 == 1) 
    result += '<b>' + matches[i] + '</b>'; 
    else 
    result += matches[i]; 
} 
+0

@fabio: quelli '. *' dovrebbero essere non-golosi - '. *?'. Inoltre, la tua regex non soddisfa i requisiti di corrispondenza di * ne 9 *. –

+0

Hai ragione, non ... Non ho notato che voleva corrispondenze anche al di fuori dell'ordine. –

+0

@ Fábio: dovresti regex-citare l'input prima di iniziare. Altrimenti +1, è meglio del mio approccio. – Tomalak

1

Semplice:

var pattern = "n univ av".replace(/\s+/, "|"); 
var rx  = new RegExp(pattern, "gi"); 
var matches = rx.Matches("N University Ave"); 

O qualcosa in questo senso.

0

Se questi sono i termini di ricerca:

  1. n univ av
  2. re BLV
  3. ne 9

Sembra il tuo algoritmo s hould essere qualcosa di simile

  1. ricerca diviso dallo spazio (risultati in termini di ricerca di matrice) input.split(/\s+/)
  2. tentativo di abbinare ogni termine entro il vostro input. /term/i
  3. per ciascun input abbinato, sostituire ogni termine con il termine racchiuso tra tag <b>. input.replace(/(term)/gi, "<b>\$1</b>")

Nota: probabilmente si vorrà prendere precauzioni per sfuggire metacaratteri regex.

+0

@macek: il punto # 3 fallisce perché 'string. replace() 'inizia sempre all'inizio della stringa, potenzialmente portando a nidificazione di tag non valida ecc. quando il secondo termine di ricerca è parte del primo, oppure il secondo termine di ricerca è' "b" '.;) – Tomalak

+0

@Tomalak, grazie il tuo metodo è molto superiore. –

+0

Fábio's è anche meglio.;) Affronta le questioni che il mio ha, ed è anche più breve. – Tomalak

2
function highlightPartial(subject, search) { 
    var special = /([?!.\\|{}\[\]])/g; 
    var spaces = /^\s+|\s+/g; 
    var parts = search.split(" ").map(function(s) { 
    return "\b" + s.replace(spaces, "").replace(special, "\\$1"); 
    }); 
    var re = new RegExp("(" + parts.join("|") + ")", "gi"); 
    subject = subject.replace(re, function(match, text) { 
    return "<b>" + text + "</b>"; 
    }); 
    return subject; 
} 

var result = highlightPartial("N University Ave", "n univ av"); 
// ==> "<b>N</b> <b>Univ</b>ersity <b>Av</b>e" 

Nota a margine - questa implementazione non prestare attenzione per abbinare ordine, quindi:

var result = highlightPartial("N University Ave", "av univ n"); 
// ==> "<b>N</b> <b>Univ</b>ersity <b>Av</b>e" 

Se questo è un problema, un approccio sequenziale più elaborato sarebbe diventato necessario, qualcosa che ho evitato qui da utilizzando una funzione di callback replace().

+0

@ Tomalak, ottima risposta. +1. Come restituiresti i risultati che corrispondono a tutti i termini? –

+0

@macek: Beh, questo richiederebbe un po 'di lavoro. Penso che scrivere un loop su tutte le parti e abbinarle singolarmente a 'subject', incrementando un contatore mentre si va, farebbe il trucco. Se il contatore corrisponde al numero di parti, tutte sono nell'input. – Tomalak

Problemi correlati