2009-08-21 3 views
6

Как я могу эмулировать ключевое слово SQL LIKE в JavaScript?Эмуляция SQL LIKE в JavaScript

Для тех из вас, кто не знает, что LIKE есть, это очень простое регулярное выражение, которое поддерживает только символы %, что соответствует 0 или больше символов, и _ которых соответствует ровно один символ.

Однако, это не только возможно, чтобы сделать что-то вроде:

var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null; 

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

+0

fyi- в примере кода вы пропускаете закрывающую скобку, прежде чем " '.exec'" – Kip

+0

@ C.ba rlow: не стесняйтесь удалять старые пометки «edit: .. blah» при редактировании.Стремитесь к «наилучшему автономному вопросу»; история редактирования доступна для всех, поэтому не нужно оставлять комментарии. :) – sarnold

+0

@sarnold Gotcha! Спасибо за руководство! –

ответ

6

То, что у вас есть, будет работать до тех пор, пока вы сначала избежите символов регулярных выражений в своем шаблоне. Ниже приведен один пример из Simon Willison’s blog:

RegExp.escape = function(text) { 
    if (!arguments.callee.sRE) { 
    var specials = [ 
     '/', '.', '*', '+', '?', '|', 
     '(', ')', '[', ']', '{', '}', '\\' 
    ]; 
    arguments.callee.sRE = new RegExp(
     '(\\' + specials.join('|\\') + ')', 'g' 
    ); 
    } 
    return text.replace(arguments.callee.sRE, '\\$1'); 
} 

Вы могли бы реализовать свой код, как:

likeExpr = RegExp.escape(likeExpr); 
var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null; 
+1

Предполагая, что у вас уже есть - RegExp.like = function (text) {return new RegExp ("^" + (RegExp.escape (текст) .replace (/%/g, ". *"). Replace (/ _/g, ".")) + "$"); } 'может быть немного более многократно использоваться для него. – gnarf

+0

Эта реализация 'Regex.escape' является довольно избыточной. Прежде всего, появление 'arguments.callee' предотвращает некоторые из оптимизаций в современных браузерах (и устарело в ES5-strict), поэтому лучше избегать его, когда это возможно. Во-вторых, есть ненужное экранирование символов, когда вместо этого они могут быть помещены в класс символов. Вот небольшая (и, скорее всего, более быстрая) версия, которую мы используем в Prototype.js - 'RegExp.escape = function (str) {return str.replace (/ ([. * +?^=!: $ {} () | [\] \/\\])/g, '\\ $ 1'); }; ' – kangax

1

Если вы хотите использовать регулярное выражение, вы можете обернуть каждый символ строки в квадратных скобках. Тогда у вас осталось всего несколько символов.

Но лучшим вариантом может быть усечение целевых строк, чтобы длина соответствовала вашей строке поиска и проверяла равенство.

2

Вот функция, я использую, основанный на PHP's preg_quote function:

function regex_quote(str) { 
    return str.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1"); 
} 

Так что ваша линия будет в настоящее время:

var match = new RegEx(regex_quote(likeExpr).replace("%", ".*").replace("_", ".")).exec(str) != null; 
3

Я искал ответ на тот же вопрос и пришел с этим после прочтения ответ Кип:

String.prototype.like = function(search) { 
    if (typeof search !== 'string' || this === null) {return false; } 
    // Remove special chars 
    search = search.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1"); 
    // Replace % and _ with equivalent regex 
    search = search.replace(/%/g, '.*').replace(/_/g, '.'); 
    // Check matches 
    return RegExp('^' + search + '$', 'gi').test(this); 
} 

Вы можете использовать его следующим образом (обратите внимание, что он игнорирует верхний/нижний регистр):

var url = 'http://www.mydomain.com/page1.aspx'; 
console.log(url.like('%mydomain.com/page_.asp%')); // true 

ПРИМЕЧАНИЕ 29/11/2013: Обновлено с RegExp.test() улучшение производительности согласно комментарию Lucios ниже.

+0

вместо !! this.match (..., вы не должны использовать this.test (...? –

+0

hi @ LucioM.Tato, x.test() метод для экземпляров RegExp, а не для String объект .. [http://www.w3schools.com/jsref/jsref_regexp_test.asp](http://www.w3schools.com/jsref/jsref_regexp_test.asp) –

+0

Простите, что я не был ясен. re получить массив соответствия (дорогое regexp) вместо использования .test (более высокая производительность). Должно быть: вернуть новый RegExp (...). test (this); вместо преобразования массива или null в boolean путем двойного отрицания. http://stackoverflow.com/questions/10940137/regex-test-vs-string-match-to-know-if-a-string-matches-a-regular-expression –

0

В ответ Криса Ван Опсталя вместо замены заменить замените вместо замены, чтобы заменить все «%» и «_». Ссылки как сделать replaceAll - here

0

Джонни пришел в последнее время здесь, но это работает для меня, я использую его для моих спа-страниц, чтобы избежать определенных страниц показывают результаты после страницы по умолчанию:

function like(haystack,needle){ 
    needle = needle.split(','); 
    var str = haystack.toLowerCase(); 
    var n = -1; 
    for(var i=0;i<needle.length;i++){ 
     n = str.search(needle[i]); 
     if(n > -1){ 
      return n; 
     } 
    } 
return n; 
} 

использование является - здесь я хочу, чтобы не показать никаких результатов на инструментах, контактных или домашних страниц - результаты() является функцией я не показываю здесь:

var n = like($data,'tools,contact,home'); 
//~ alert(n); 
if(n < 0){// does not match anything in the above string 
    results($data); 
} 
Смежные вопросы