вторник, 14 февраля 2012 г.

JavaScript. Поиск строки методом like (аналог like из MySQL)

Недавно, мне понадобилось осуществлять поиск по массиву объектов(со строковыми полями). В JavaScript, сложный поиск осуществляется с помощью регулярных выражений, для того чтобы искать в контексте объекта String, есть метод(прототип) match().

Но так как задача похожа на поиск по БД, то мне захотелось использовать синтаксис поиска MySQL функции like() - она очень удобна, когда не нужно явно применять поиск по сложному регулярному выражению. Например: поиск строк начинающихся, заканчивающихся какой-то подстрокой или включают подстроку (что совпадало с моей задачей).

Плюс ко всему - нужно уметь динамически генерировать это условие. Конечно, в JavaScript легко создать регулярное выражение из строки с помощью конструктора new RegExp(pattern, attrs), но это не так красиво как использование like. Потому я расширил прототип String этим методом. Внутри он таки использует регулярные выражения, но от программиста это скрыто, и пользоваться этим удобно и интуитивно всем кто знает SQL.

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

String.prototype.like = function(s) {
  if(undefined==s || typeof(s)!='string') return false;

  function replacer(str, p1, p2) {
    if(p1=='\\') return p2;
    if(p2=='%') return p1+'.+';
    return p1+'\\w';
  }
  
  var pattern = "^"+s.replace(/(.|^)([%_])/gm, replacer)+'$'; 
  var re = new RegExp(pattern, 'mg');

  if(this.match(re)) return true;
  return false;
};

Пример использования:

var s = "Test string";

console.log( s.like("%ing")  ); // True
console.log( s.like("%in")   ); // False
console.log( s.like("%in_")  ); // True
console.log( s.like("Test%") ); // True
console.log( s.like("%str%") ); // True
console.log( s.like("%spr%") ); // False
console.log( s.like("%s_r%") ); // True


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

3 комментария:

  1. Не совсем, конечно, хорошо прямо к стандартному объекту String добавлять функцию like. Особенно, когда идет разработка командой. В один прекрасный момент можно будет обнаружить кучу недокументированных возможностей у объекта String :) А сама идея интересная. И не забыть экранировать символы "[", "]" и другие служебные.

    ОтветитьУдалить
  2. нехорошо расширять прототип Object, так как тогда надо во всех переборах хешей обязательно проверять .hasOwnProperty() - тоесть отсеивать сторонние ключи которые добавяться при расширении прототипа. А если в проекте команде запрещено расширять прототип Object - проверку можно опустить (хотя согласно правильным подходам программирования она должна всегда быть)

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

    ОтветитьУдалить