如何创建搜索语言?

时间:2014-07-11 08:50:19

标签: javascript parsing search string-parsing

我想在Javascript中创建一个简单的过滤语言。

我想搜索一系列产品,比如说:

product=[
   {price:10,name:"T-Shirt",category:"Clothing",published_at:"07-08-2014",size:"10x30",color:"#0000FF"},
   {price:20,name:"Chair",category:"Furniture",published_at:"09-03-2013",size:"30x30",color:"#00FF00"},
   {price:30,name:"iPhone",category:"Phones",published_at:"17-03-2014",size:"40x30",color:"#FF00FF"},
   {price:40,name:"Samsung Galaxy",category:"Phones",published_at:"12-01-2012",size:"10x60",color:"#00BBBB"},
];

只有一个文本输入,我希望能够在这个数组中查询,例如:

  • cat:Clothing =>回馈T恤
  • price:>15 =>给予椅子,iPhone和三星Galaxy
  • name:iP =>通过名称过滤并返回iPhone
  • price:>15&&size:>35x25 =>通过名称过滤并返回iPhone

我知道他们是一些像

这样的语言解析器

但我不知道选择哪一个(以及为什么)以及使用哪一个是个好主意?有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我认为这很简单,没有图书馆就可以自己做。

这是我对它的抨击:

<强> http://jsfiddle.net/qrz48/2/

// polyfill Array.prototype.forEach if you need to support older browsers...
// there's one at: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

var product = [
    {price:10,name:"T-Shirt",category:"Clothing",published_at:"07-08-2014",size:"10x30",color:"#0000FF"},
    {price:20,name:"Chair",category:"Furniture",published_at:"09-03-2013",size:"30x30",color:"#00FF00"},
    {price:30,name:"iPhone",category:"Phones",published_at:"17-03-2014",size:"40x30",color:"#FF00FF"},
    {price:40,name:"Samsung Galaxy",category:"Phones",published_at:"12-01-2012",size:"10x60",color:"#00BBBB"}
];

// extend this as you require new search operators.
var operators = {
    "==": function(a, b) {return a == b;},
    "===": function(a, b) {return a === b;},
    ">": function(a, b) {return a > b;},
    ">=": function(a, b) {return a >= b;},
    "<": function(a, b) {return a < b;},
    "<=": function(a, b) {return a <= b;},
    "*": function(a, b) {return a.indexOf(b) > -1;}
};

// usage: find("category", "===", "Clothing")
function find(key, operator, condition, searchIn) {
    if( ! searchIn) {
        searchIn = product;
    }
    var result = [];
    searchIn.forEach(function(item) {
        if(operators[operator](item[key], condition)) {
            result.push(item);
        }
    });
    return result;
}

// usage: query("category:===:Clothing");
function query(str) {
    var conditions = str.split("&&");
    var result = [];
    conditions.forEach(function(condition, index) {
        var parts = condition.split(":");
        var key = parts[0];
        var operator = parts[1];
        var condition = parts[2];
        var searchIn = (conditions.length > 1 && index > 0) ? result : null;
        result = find(key, operator, condition, searchIn);
    });
    return result;
}


// usage
console.log(query("category:===:Clothing"));
console.log(query("price:>:20"));
console.log(query("name:*:iP"));
console.log(query("price:>:20&&name:*:Galaxy"));

您可以根据请求将搜索字符串传递给上面的query函数,但条件运算符之前和之后都需要冒号。例如,要查找价格大于20的所有产品,请运行:

query("price:>:20");

您还可以使用问题中的格式组合搜索条件:

query("price:>:20&&category:===:Clothing");

我无法想象如何在不将大小数据拆分为单独的值的情况下进行size比较,例如: sizeXsizeY,使用

等比较容易比较
query("sizeX:>:30&&sizeY:>:20");

如果有什么事情可以写得很有趣。你怎么看?

答案 1 :(得分:0)

我决定用JISON(类似于BISON)进行测试

/* description: Parses end executes mathematical expressions. */

/* lexical grammar */
%lex
%%

\s+                   /* skip whitespace */
[0-9]+("."[0-9]+)?\b  return 'NUMBER'
">"                     return '>'
"price:"              return 'PRICE'
<<EOF>>               return 'EOF'
"name:"               return 'NAME'
[a-z]+                return 'STRING'
","                   return 'COMMA'


/lex

/* operator associations and precedence */

%left 'COMMA'
%left 'PRICE' 'NAME'


%start expressions

%% /* language grammar */

expressions
    : e EOF
        { typeof console !== 'undefined' ? console.log($1) : print($1);
          return $1; }
    ;

e
    : 'PRICE' '>' e
        {$$ = {price:{gt:$3}};}
    | 'NAME' e
        {$$ = {name:{contains:$2}};}
    | NUMBER
        {$$ = Number(yytext);}
    | STRING
        {$$ = String(yytext);}
    | e 'COMMA' e
        { for (var attrname in $1) { $3[attrname]=$1[attrname]; $$ = $3; }}
    ;

解析器的结果如下:

price:>30 =&gt; { price: { gt: 30 } }

name:blabla,price:>10 =&gt; { price: { gt: 10 }, name: { contains: 'blabla' } }

name:test =&gt; { name: { contains: 'test' } }

这个解决方案对我来说似乎更容易移植,因为它不直接处理解析。