考虑文本框中的以下字符串:
([员工]。[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;
}
}
第一个字符串适用于此,但第二个字符串太复杂。
对此有何帮助?
如果需要,我会编辑问题。
答案 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);
使用你的例子,我得到的第一个是有效的,第二个是无效的。 ([实体]。[标题]不合法)。