2010-04-16 3 views
6

Я хотел бы создать безрежимное регулярное выражение (для JavaScript), которое соответствует названиям улиц, даже если каждое слово было сокращено. Например:Регулярное выражение для частичных слов (JavaScript)

п унив ав должен соответствовать N Univ ersity Av е

король BLV должен соответствовать Мартин Лютер Кинг младший BLV d

пе 9-й должен соответствовать как NE 9th St и 9-й St NE

Бонусные баллы (JK) для "заменить" регулярных выражений, который оборачивает совпавший текст <b> тегов.

+8

Как это отмечено «весело», цитируя Джейми Завински: «Некоторые люди, столкнувшись с проблемой, думают« Я знаю, я буду использовать регулярные выражения ». Теперь у них есть две проблемы. * –

+0

@Pascal: отличная цитата. –

+0

@ Энди: Теперь вы должны быть единственным программистом * на земле *, который еще не сталкивался с этой конкретной цитатой. ;) Со своей стороны, мне это надоело. oO – Tomalak

ответ

11

Вы получили:

"n univ av" 

Вы хотите:

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

Так вы:

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

вуаля!

Но я не закончил, мне нужны мои бонусные очки.Таким образом, мы изменим шаблон для:

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

И потом:

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

Теперь мы получили:

  • матчи [0] => все выражение (бесполезный)
  • матчи [even] => один из наших совпадений
  • соответствует [odd] => дополнительный текст не в исходной строке соответствия

Таким образом, мы можем написать:

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: эти '. *' должны быть неживыми - '. *?'. Кроме того, ваше регулярное выражение не удовлетворяет требованиям соответствия * ne 9th *. –

+0

Вы правы, это не ... Я не заметил, что ему нужны матчи вне порядка. –

+0

@ Fábio: вы должны regex-котировать ввод перед тем, как начать. В противном случае +1, это лучше, чем мой подход. – Tomalak

1

Простой:

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

Или что-то вдоль этих линий.

0

Если эти условия поиска:

  1. п унив пр
  2. король BLV
  3. пе девятым

Это звучит как ваш алгоритм s hould быть что-то вроде этого

  1. поиска по раздельным пространству (результаты поиска в массиве терминов) input.split(/\s+/)
  2. попытки соответствовать каждому члену внутри вашего входа. /term/i
  3. для каждого согласованного ввода, заменить каждый термин термином, заключенным в теги <b>. input.replace(/(term)/gi, "<b>\$1</b>")

Примечание: Вы, вероятно, хотите, чтобы принять меры предосторожности, чтобы избежать регулярных выражений метасимволы.

+0

@macek: Точка №3 терпит неудачу, потому что 'string. replace() 'всегда начинается с начала строки, что потенциально приводит к недопустимому вложенности тегов и т. д., когда второй поисковый запрос является частью первого. Или второй поисковый термин« b »'.;) – Tomalak

+0

@Tomalak, thanks для вашего ловли. Ваш метод очень высок. –

+0

Fábio's еще лучше.;) Он решает проблемы, которые у меня есть, и также короче. – 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" 

Примечание стороны - это реализация не обращать внимание на соответствие порядка, так:

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

Если это проблема, более сложный последовательный подход мог бы стать необходимым, то, что я избегал здесь используя функцию обратного вызова replace().

+0

@Tomalak, отличный ответ. +1. Как бы вы только вернули результаты, соответствующие всем условиям? –

+0

@macek: Ну, это потребует некоторой работы. Я думаю, что писать петлю по всем частям и сопоставлять их по отдельности с «субъектом», увеличивая счетчик, как вы идете, сделает трюк. Если счетчик соответствует количеству деталей, все они находятся на входе. – Tomalak

Смежные вопросы