我想在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 我知道他们是一些像
这样的语言解析器但我不知道选择哪一个(以及为什么)以及使用哪一个是个好主意?有什么想法吗?
答案 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
比较,例如: sizeX
和sizeY
,使用
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' } }
这个解决方案对我来说似乎更容易移植,因为它不直接处理解析。