簡體   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