验证查询参数并使用正则表达式对其进行解析

Validating the query parameter and parsing it using regular expression

我是正则表达式的新手,你能告诉我如何使用以下所有组合获取查询参数吗?

(ParamName=Operator:ParamValue) 是我的一组查询参数值。这将用 ;(AND) 或 ,(OR) 分隔,我想将它们分组在大括号内。就像下面的例子

例如:http://,host:port>/get?search=(date=gt:2020-02-06T00:00:00.000Z;(name=eq:Test,department=co:Prod)) 这里的日期应该大于 2020-02-06 并且 name = Test or department contains Prod。 如何解析这些查询参数。请提出建议。

谢谢,维杰

所以,我在 JavaScript 中写了一个解决方案,但经过一些研究,它应该也适用于其他语言。

这是相当多的代码,但您要实现的目标并不容易!

所以这是下面的代码,它有详尽的注释,但是如果你有什么不明白的地方,请提出来,我很乐意回答你:)

//
// The 2 first regexes are a parameter, which looks like date=gt:2020-02-06T00:00:00.000Z for example.
// The difference between those 2 is that the 1st one has **named capture group**
//      For example '(?<operator>...)' is a capture group named 'operator'.
//      This will come in handy in the code, to keep things clean
//
const RX_NAMED_PARAMETER = /(?:(?<param>\w+)=(?<operator>\w+):(?<value>[\w-:.]+))/
const parameter = "((\w+)=(\w+):([\w-:.]+)|(true|false))"

//
// The 3rd parameter is an operation between 2 parameters
//
const RX_OPERATION = new RegExp(`\((?<param1>${parameter})(?:(?<and_or>[,;])(?<param2>${parameter}))?\)`, '');
//                                   '---------.---------'  '-------.------'  '----------.---------' 
//                                       1st parameter          AND or OR          2nd parameter


my_data = {
    date: new Date(2000, 01, 01),
    name: 'Joey',
    department: 'Production'
}


/**
 * This function compates the 2 elements, and returns the bigger one.
 * The elements might be dates, numbers, or anything that can be compared.
 * The elements **need** to be of the same type
 */
function isGreaterThan(elem1, elem2) {
    if (elem1 instanceof Date) {
        const date = new Date(elem2).getTime();
        if (isNaN(date))
            throw new Error(`${elem2} - Not a valid date`);

        return elem1.getTime() > date;
    }
    if (typeof elem1 === 'number') {
        const num = Number(elem2);
        if (isNaN(num))
            throw new Error(`${elem2} - Not a number`);

        return elem1 > num;
    }
    return elem1 > elem2;
}

/**
 * Makes an operation as you defined them in your
 * post, you might want to change that to suit your needs
 */
function operate(param, operator, value) {
    if (!(param in my_data))
        throw new Error(`${param} - Invalid parameter!`);

    switch (operator) {
        case 'eq':
            return my_data[param] == value;
        case 'co':
            return my_data[param].includes(value);
        case 'lt':
            return isGreaterThan(my_data[param], value);
        case 'gt':
            return !isGreaterThan(my_data[param], value);
        default:
            throw new Error(`${operator} - Unsupported operation`);
    }
}

/**
 * This parses the URL, and returns a boolean
 */
function parseUri(uri) {

    let finalResult;

    // As long as there are operations (of the form <param1><; or ,><param2>) on the URL
    while (RX_OPERATION.test(uri)) {

        // We replace the 1st operation by the result of this operation ("true" or "false")
        uri = uri.replace(RX_OPERATION, rawOperation => {

            // As long as there are parameters in the operations (e.g. "name=eq:Bob")
            while (RX_NAMED_PARAMETER.test(rawOperation)) {

                // We replace the 1st parameter by its value ("true" or "false")
                rawOperation = rawOperation.replace(RX_NAMED_PARAMETER, rawParameter => {
                    const res = RX_NAMED_PARAMETER.exec(rawParameter);

                    return '' + operate(
                        res.groups.param,
                        res.groups.operator,
                        res.groups.value,
                    );
                    // The "res.groups.xxx" syntax is allowed by the
                    // usage of capture groups. See the top of the file.
                });
            }
            
            // At this point, the rawOperation should look like
            // (true,false) or (false;false) for example

            const res = RX_OPERATION.exec(rawOperation);

            let operation;
            if (res.groups.param2 === undefined)
                operation = res.groups.param1; // In case this is an isolated operation
            else
                operation = res.groups.param1 + ({',': ' || ', ';': ' && '}[res.groups.and_or]) + res.groups.param2;

            finalResult = eval(operation);
            return '' + finalResult;
        });
    }

    return finalResult;
}

let res;

res = parseUri("http://,host:port>/get?search=(date=gt:2020-02-06T00:00:00.000Z;(name=eq:Test,department=co:Prod))");
console.log(res);

res = parseUri("http://,host:port>/get?search=(date=lt:2020-02-06T00:00:00.000Z)");
console.log(res);