Эмуляция SQL как в JavaScript - PullRequest
       19

Эмуляция SQL как в JavaScript

9 голосов
/ 22 августа 2009

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

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

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

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

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

Ответы [ 8 ]

10 голосов
/ 22 августа 2009

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

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;
4 голосов
/ 24 августа 2013

Я искал ответ на тот же вопрос и придумал его после прочтения ответа Кипа:

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 ниже.

2 голосов
/ 22 августа 2009

Вот функция, которую я использую на основе PHP-функции preg_quote :

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

Итак, ваша строка теперь будет:

var match = new RegEx(regex_quote(likeExpr).replace("%", ".*").replace("_", ".")).exec(str) != null;
1 голос
/ 23 мая 2018

Старый вопрос, но здесь нет хороших ответов. Выражения TSQL LIKE могут содержать экранированные квадратные скобки разделы, которые уже являются почти допустимыми регулярными выражениями и допускают сопоставление % и _. E.g.:

'75%' LIKE '75[%]'
'[foo]' LIKE '[[]foo]' -- ugh

Вот моя функция для преобразования выражения LIKE в RegExp. Вход делится на квадратные и не квадратные секции. Секции в квадратных скобках просто необходимо экранировать от обратной косой черты, а секции, не содержащие квадратных скобок, полностью экранируются, а директивы % и _ преобразуются в регулярные выражения.

const likeRegExp = (expression, caseSensitive = false) =>
    new RegExp(`^${
        expression.split(/(\[.+?\])/g)
        .map((s, i) => i % 2 ?
            s.replace(/\\/g, '\\\\') :
            s.replace(/[-\/\\^$*+?.()|[\]{}%_]/g, m => {
                switch(m) {
                    case '%': return '.*';
                    case '_': return '.';
                    default: return `\\${m}`;
                }
            })
        ).join('')
    }$`, caseSensitive ? '' : 'i');
1 голос
/ 22 августа 2009

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

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

0 голосов
/ 31 мая 2019

Я хотел что-то, что также обрабатывает экранирование символов % и _, используя \% и \_.

Вот мое решение, использующее отрицательный взгляд:

// escapes RegExp special characters
const escapePattern = s => s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');

// converts ILIKE pattern to a RegExp object
const ilikeToRegExp = pattern =>
  new RegExp(
    `^${escapePattern(pattern)}$`
      // convert ILIKE wildcards, don't match escaped
      .replace(/(?<![\\])%/g, '.*')
      .replace(/(?<![\\])_/g, '.')
      // replace ILIKE escapes
      .replace(/\\%/g, '%')
      .replace(/\\_/g, '_'),
    'i'
  );

Использование:

ilikeToRegExp('%eLlo WoR%').test('hello world')  
// true

ilikeToRegExp('ello wor').test('hello world')  
// false

ilikeToRegExp('%90\%%').test('...90%...') 
// true
0 голосов
/ 14 мая 2016

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

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;
}

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

var n = like($data,'tools,contact,home');
//~ alert(n);
if(n < 0){// does not match anything in the above string
  results($data);
}
0 голосов
/ 04 февраля 2014

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

...