[英]how can i parse a "query notation" string?
假设我有一项服务可以从一些数据 object(例如 ArrayList)中获取 Items 的数据。 该服务实现了一种方法,该方法将查询作为字符串获取,并返回适合查询的项目列表 - 就这么简单。 方法签名:public List query (String query) {}
现在面临挑战:查询以前缀方式构建,由一个或多个“类似 SQL”的查询选项组成:EQUAL、GREATER_THAN、LESS_THAN、AND、OR、NOT,每个选项都有一个括号用逗号分隔的字段名称和值(一个项目)。 例子:
"EQUAL(id,\"id2\")" -> search for item with id = "id2"
"OR(EQUAL(id,\"id1\"),EQUAL(id,\"id2\"))" -> search for items with id = "id1" or id = "id2"
"GREATER_THAN(views,41)" -> search for item with views > 41
更复杂的例子:
"OR(EQUAL(id,\"id1\"),AND(GREATER_THAN(views,100),EQUAL(id,\"id2\")))"
你知道一些开箱即用的解析器吗? 或者知道如何解析它?
提前致谢。
我仍然坚持思考如何一般地解析这个查询,尤其是考虑 NOT、AND 或 OR 的优先级
它采用明确的格式(您不必担心优先级),其中第一个元素始终是运算符,操作数在括号中。 由于可以嵌套,因此我建议采用类似于以下的递归方法:
record IntermediateResult(Evaluator<YourType> evaluator, int lastIndex){};
sealed interface Operand permits EvaluatedOperand, DirectOperand{}
record EvaluatedOperand(Evaluator<YourType> operand) implements Operand{}
record DirectOperand(String operand)
public IntermediateResult parse(String toParse, int startIndex){
//find the start of the operands or the end of the operand if the it isn't an expression to parse
//TODO handle double quotes here
int openBrackStart=toParse.indexOf("(",startIndex);
int nextClosedBrack=toParse.indexOf(")",startIndex);
if(nextClosedBrack==-1){
nextClosedBrack=toParse.length();
}
int nextComma=toParse.indexOf(",",startIndex);
if(nextComma==-1){
nextComma=toParse.length();
}
int operandEnd=Math.min(nextClosedBrack,nextComma);
if(openBrackStart==-1||openBrackStart>operandEnd){
return new IntermediateResult(null, operandEnd);//no subexpressions, it's just an operand
}
//there are subexpressions (inside parenthesis) - parse those
String operator=toParse.substring(startIndex,openBrackStart);
int numOperands=getNumberOfOperands(operator);
Operand[] operands=new Operand[numOperands];
int operandStart=openBrackStart+1;
for(int i=0;i<numOperands;i++){
//parse each operator
IntermediateResult subExpression=parse(toParse, operandStart);
if(subExpression.evaluator()==null){
//operator doesn't have subexpressions
operands[i]=new DirectOperand(toParse.substring(operandStart, subExpression.lastIndex()));
}else{
//operator has subexpressions
operands[i]=new EvaluatedOperand(subExpression.evaluator());
}
operandStart=subExpression.lastIndex()+1;
}
return new IntermediateResult(getEvaluatorForOperator(operator, operands), operandStart)
}
请注意,这只是一个草图/我没有测试它,也没有检查边缘情况,但它应该给出一个粗略的想法:
它检查是否有子表达式。 如果没有,它会返回一个不需要进一步解析的IntermediateResult
( evaluator
为null
)。 (或者,可以为此使用密封接口。)
如果有子表达式,它会提取运算符,然后通过递归解析来识别操作数。 如果不需要计算它们,则将它们保存为DirectOperand
,如果需要,则将它们保存为EvaluatedOperand
。 然后,它继续执行下一个操作数。 为此,它需要知道运算符 ( getNumberOfOperands()
) 有多少个操作数。
解析表达式后,将返回一个新的IntermediateResult
,其中包含一个 object,其中包含有关如何评估表达式(来自getEvaluatorForOperator
)和已解析表达式结尾的信息。
为简单起见,我没有处理无效的查询字符串或双引号(如前所述,这只是一个草图),但添加它应该不会太难。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.