繁体   English   中英

我如何解析“查询符号”字符串?

[英]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)
}

请注意,这只是一个草图/我没有测试它,也没有检查边缘情况,但它应该给出一个粗略的想法:

它检查是否有子表达式。 如果没有,它会返回一个不需要进一步解析的IntermediateResultevaluatornull )。 (或者,可以为此使用密封接口。)

如果有子表达式,它会提取运算符,然后通过递归解析来识别操作数。 如果不需要计算它们,则将它们保存为DirectOperand ,如果需要,则将它们保存为EvaluatedOperand 然后,它继续执行下一个操作数。 为此,它需要知道运算符 ( getNumberOfOperands() ) 有多少个操作数。

解析表达式后,将返回一个新的IntermediateResult ,其中包含一个 object,其中包含有关如何评估表达式(来自getEvaluatorForOperator )和已解析表达式结尾的信息。

为简单起见,我没有处理无效的查询字符串或双引号(如前所述,这只是一个草图),但添加它应该不会太难。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM