2010-04-16 40 views
6

Me gustaría crear una expresión regular (para JavaScript) que no coincida con mayúsculas y minúsculas, que coincida con los nombres de las calles, incluso si cada palabra se ha abreviado. Por ejemplo:Regex para que coincida con palabras parciales (JavaScript)

n Univ av debe coincidir N Univ ersidadAv e

rey BLV debe coincidir con Martin Luther Rey Jr. Blv d

ne 9º debe coincidir con NE 9º St y St NE

puntos de bonificación (JK) para una expresión regular "reemplazar" que envuelve el texto que coincide con <b> etiquetas.

+8

Como esto está etiquetado como "diversión", citando a Jamie Zawinski: * Algunas personas, cuando se enfrentan con un problema, piensan "Lo sé, usaré expresiones regulares". Ahora tienen dos problemas. * –

+0

@Pascal: excelente presupuesto. –

+0

@Andy: ahora debes ser el único programador * en la tierra * que aún no se haya enfrentado a esa cita en particular. ;) Por mi parte, estoy harto de eso. oO – Tomalak

Respuesta

11

Usted tiene:

"n univ av" 

que desee:

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

Así lo hace:

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

Voilà!

Pero no he terminado, quiero mis puntos de bonificación.Así que cambiamos el patrón a:

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

Y luego:

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

Ahora tenemos:

  • coincidencias [0] => toda la expresión (inútil)
  • partidos [incluso] => una de nuestras coincidencias
  • coincide con [impar] => texto adicional no en la secuencia de coincidencia original

Por lo tanto, podemos escribir:

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: esos '. *' deben ser no codiciosos - '. *?'. Además, su expresión regular no cumple con el requisito de coincidencia de * ne 9º *. –

+0

Tienes razón, no ... No me di cuenta de que quería los partidos fuera de la orden también. –

+0

@ Fábio: Debería regex-quote la entrada antes de comenzar. De lo contrario +1, eso es mejor que mi enfoque. – Tomalak

1

simple:

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

O algo en este sentido.

0

Si estos son los términos de búsqueda:

  1. n Univ av
  2. rey BLV
  3. NE 9th

Parece que tu algoritmo hould ser algo como esto

  1. búsqueda dividida por el espacio (resultados en términos de búsqueda matriz) input.split(/\s+/)
  2. intento para que coincida con cada término dentro de su entrada. /term/i
  3. para cada entrada coincidente, reemplace cada término con el término envuelto en etiquetas <b>. input.replace(/(term)/gi, "<b>\$1</b>")

Nota: Probablemente tendrá que tomar precauciones para escapar metacaracteres de expresiones regulares.

+0

@macek: El punto # 3 falla porque 'string. replace() 'siempre comienza al comienzo de la cadena, lo que puede conducir al anidamiento de etiquetas no válido, etc. cuando el segundo término de búsqueda es parte del primero. O el segundo término de búsqueda es' "b" '.;) – Tomalak

+0

@Tomalak, gracias para atrapar esto. Su método es muy superior. –

+0

Fábio es aún mejor.;) Se ocupa de los problemas que tiene la mina, y es más corto, también. – 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 al margen - Esta implementación no prestar atención para que coincida con el fin, por lo que:

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

Si eso es un problema, sería necesario un enfoque secuencial más elaborado, algo que he evitado aquí utilizando una función de devolución de llamada replace().

+0

@Tomalak, gran respuesta. +1. ¿Cómo solo devolverá los resultados que coinciden con todos los términos? –

+0

@macek: Bueno, eso requeriría algo de trabajo. Creo que escribir un ciclo sobre todas las partes e igualarlas individualmente con 'sujeto', aumentar un contador sobre la marcha haría el truco. Si el contador coincide con el número de partes, todas están en la entrada. – Tomalak

Cuestiones relacionadas