检查句子是否是一个SQL查询并在c#中除以句子

时间:2017-11-01 12:46:04

标签: c# sql string linq

考虑文本框中的以下字符串:

  

([员工]。[Id] =   ' 00000001-0001-0000-0000-000000000000'和[员工]。[姓名] =   '向导'和[员工]。[标题] ='事件')

  

([员工]。[Id] =' 00000001-0001-0000-0000-000000000000' AND   [员工]。[组] =' XYZ' AND([Entity]。[Title] IS NULL OR   [员工]。[标题] ='向导')和[员工]。[子组]是空和   [员工]。[团队] IS NULL)

上述查询基本上是任何SQL语句中的WHERE子句。

我在DB中将一组函数存储为单独的行中的字符串:

  

=,> =,< =,AND,OR,CONTAINS,IS NULL,STARTSWITH&的endsWith。

我需要做以下事情:

1)检查文本框是否为空

2)检查文本框是否附有方括号(和)

3)检查查询是否仅由DB中可用的函数分隔。

4)检查是否必须使用[Employee]启动每个属性。标签

5)将属性及其值存储在某个列表中

到目前为止,我已经做到了这一点:

    static bool IsRuleValid(string rule)
    {
        try
        {
            Dictionary<string, string> keyValue = new Dictionary<string, string>();

            if (rule.Length > 0 && rule.Trim().Length == 0)
            {
                return false;
            }
            else
            {
                if (rule[0] == '(' && rule[rule.Length - 1] == ')')
                {
                    //remove brackets
                    rule = rule.Remove(0, 1);
                    rule = rule.Remove((rule.Length - 1), 1);

                    //find first =
                    while (!string.IsNullOrEmpty(rule))
                    {
                        int keyIndex = rule.IndexOf("=");
                        string bracketString = rule.Substring(0, keyIndex).Trim();

                        //find left .

                        int bracketIndex = bracketString.IndexOf('.');

                        string leftSubString = bracketString.Substring(0, bracketIndex).Trim();

                        if (leftSubString == "[Employee]")
                        {
                            string rightSubString = bracketString.Substring(bracketIndex + 1, (bracketString.Length - (bracketIndex + 1)));

                            string rightstrBetweenBigBrackets = rightSubString.Substring(rightSubString.IndexOf('[') + 1, rightSubString.IndexOf(']') - 1);

                            //find ''
                            int valueIndexStart = rule.IndexOf("'");
                            int valueIndexEnd = rule.IndexOf("'", rule.IndexOf("'") + 1) - valueIndexStart;

                            //find value between ''
                            string value = rule.Substring(valueIndexStart + 1, valueIndexEnd - 1);


                            keyValue.Add(rightstrBetweenBigBrackets, value);

                            int toremoveIndex = rule.IndexOf("'", rule.IndexOf("'") + 1);

                            rule = rule.Remove(0, toremoveIndex + 1).Trim();

                            if (rule.Length > 0)
                            {
                                int functionIndex = rule.IndexOf(" ");

                                string funcName = rule.Substring(0, functionIndex);

                                rule = rule.Remove(0, functionIndex + 1).Trim();
                            }
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    return false;
                }
            }
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

第一个字符串适用于此,但第二个字符串太复杂。

对此有何帮助?

如果需要,我会编辑问题。

1 个答案:

答案 0 :(得分:1)

这是您的语法的基本解析器。

将您允许的功能解析为List<string>。我不得不更换&#34; IS NULL&#34;用&#34; IS&#34;并且有#34; NULL&#34;是一个操作数,因为解析器不是为后缀monadic运算符编写的。这允许一些额外的非法组合,但现在还没有检查,我认为这不是一个大问题。

List<string> functions = new List<string> {
    "=", ">=", "<=", "AND", "OR", "CONTAINS", "IS", "STARTSWITH", "ENDSWITH"
};

使用包装器函数启动解析器:

private bool TryParseSQL(string strSQL, out List<string> attribs) {
    attribs = new List<string>();

    return TryParseSQLExpr(ref strSQL, ref attribs);
}

解析器有一个状态变量来决定它所期望的内容,包括父级表达式,属性或常量或函数:

enum ExprState { Expression, Function };

现在我们可以尝试解析表达式。这并没有强制执行&#39;(&#39;围绕外部要求,但如果需要,您可以在包装函数中添加它。

private bool TryParseSQLExpr(ref string strSQL, ref List<string> attribs, ExprState state = ExprState.Expression) {
    bool ans = true;

    while (strSQL.Length > 0 && ans) {
        strSQL = strSQL.TrimStart();

        var skipLen = 0;
        switch (state) {
            case ExprState.Expression:
                if (strSQL.StartsWith("(")) { // parenthized subexpression
                    strSQL = strSQL.Substring(1);
                    var tmpans = TryParseSQLExpr(ref strSQL, ref attribs);
                    if (strSQL.StartsWith(")"))
                        skipLen = 1;
                    else
                        ans = false;
                }
                else if (strSQL.StartsWith("[Employee].")) { // attribute reference
                    var attribMatch = Regex.Match(strSQL, @"\[Employee\].\[\w+\]");
                    if (attribMatch.Success) {
                        attribs.Add(attribMatch.Value);
                        skipLen = attribMatch.Value.Length;
                    }
                    else
                        ans = false;
                }
                else if (strSQL.StartsWith("'")) { // constant
                    var endOfConstant = strSQL.IndexOf('\'', 1);
                    if (endOfConstant > 0)
                        skipLen = endOfConstant+1;
                    else
                        ans = false;
                }
                else if (strSQL.StartsWith("NULL")) // NULL
                    skipLen = 4;
                else
                    ans = false;

                state = ExprState.Function;
                break;

            case ExprState.Function:
                var strSqlCopy = strSQL;
                var fn = functions.Where(f => strSqlCopy.StartsWith(f)).FirstOrDefault();
                if (fn != null) {
                    skipLen = fn.Length;
                    state = ExprState.Expression;
                }
                else
                    ans = false;
                break;
        }
        strSQL = strSQL.Substring(skipLen);
    }

    return ans;
}

您可以通过传入变量来调用解析器来保存属性:

List<string> attribs;

var valid = TryParseSQL(s1, out attribs);

使用你的例子,我得到的第一个是有效的,第二个是无效的。 ([实体]。[标题]不合法)。