【问题标题】:Validation of data that 'closely resembles' a where clause验证“非常类似于”where 子句的数据
【发布时间】:2011-06-24 15:34:40
【问题描述】:

我正在研究用户输入的验证逻辑,该逻辑非常接近于 sql where 子句。

在页面上,用户可以从下拉列表的组合中进行选择(其中“-”字符表示最后一个子句中的空白字符):

DropDown1   DropDown2       DropDown3   DropDown4   DropDown5  DropDown6

-           -               -           -           -          -
(           SomeCriteria    =           Value       )          AND
                            <>                                 OR

不幸的是,我对如何验证这个子句没有任何硬性要求,除了它应该“表现得像一个 sql where 子句”:(

一些应该通过验证

(Criteria = Value)
(criteria1 = Value1 OR Criteria2 <> value2)
(criteria1 = value1) AND (Criteria2 = value2)
(criteria1 = value1) OR (Criteria2 = value2 AND criteria3 = value3)

一些应该无法通过验证的:

)Criteria = value) (first character is not  '(' )
(Criteria = value(  (last character is not  ')' )
((Criteria = value)  (# of '(' does not match # of ')' )

(Criteria = Value (AND Criteria1 = value1))  ( 'AND' and 'OR' should not be immediately preceded  or followed by a '('  or ')' character.

对于编写正则表达式来验证这些选择的任何帮助将不胜感激。在四处闲逛之后,我看到其他人谈到 sql 解析器对于这个“受限”where 子句会是一个更好的解决方案吗?

【问题讨论】:

  • 用户是否将为每个“行”输入自定义值和标准?还是他们只是从预定义的值/标准列表中选择?
  • 没有正则表达式可以验证括号的平衡,除非您对问题添加更多约束
  • 哦,好吧,我明白你关于需要括号的意思了。不过这里不需要正则表达式。
  • 用户如何指定条件?因为我真的看不出需要 7 个下拉菜单,所以只有 1 个下拉菜单和一个添加按钮不是更聪明吗?那样它会一点一点组装起来,你可以展示给用户看吗?这也为您提供了防止用户输入明显非法值的机会(例如,在添加打开之前没有右括号)。
  • @Kelrond 你是对的。因为用户如何制作这样的 stmt: (A == B AND B != C OR (A == B OR (A == C))) 一次带有 3 个右括号..

标签: .net regex parsing validation where-clause


【解决方案1】:

注意:对于用户需要做出如下声明的情况:(A == B AND B != C OR (A == B OR (A == C))),只有在左括号下拉列表和右括号下拉列表中为用户提供更多选项时,您的解决方案才有效列表。左括号下拉列表应包括以下选项:'(', '((', '(((', '((((',您可以将其限制为连续 4 个左括号。右括号下拉列表应该看起来相同。

您可以将下拉列表放在中继器中,以便 .Net 为每个下拉列表分配一个唯一 ID。

验证码:

// this will keep track of left brackets that have not been closed
int numUnclosedLeftBrackets = 0;


// changing dropdown instance names for clarity
ddlLeftBracket == DropDown1;
ddlCriteria == DropDown2;
ddlConOperator == DropDown3;
ddlValue == DropDown4;
ddlRightBracket = DropDown5;
ddlExtension == DropDown6;

Boolean isValidStmt = false;
Boolean areValidBrackets = false;
Boolean addAnotherStmt = false;

// conditional operator dropdown cannot be blank
if(ddlConOperator.SelectedIndex > 0)
{
    if(ddlConOperator.SelectedValue == "=" && ddlCriteria.SelectedValue == ddlValue.SelectedValue)
        isValidStmt = true;
    if(ddlConOperator.SelectedValue == "<>" && ddlCriteria.SelectedValue != ddlValue.SelectedValue)
        isValidStmt = true;

    // check if both left and right brackets exist, or if both do not exist.
    if((ddlLeftBracket.SelectedIndex == 0 && ddlRightBracket.SelectedIndex == 0) || 
               (ddlLeftBracket.SelectedIndex > 0 && ddlRightBracket.SelectedIndex > 0)) 
        areValidBrackets = true;

    // check if AND, or OR is attached
    if(ddlExtension.SelectedIndex != 0)
    {
        addAnotherStmt = true;

        // check if brackets need to be validated now that the where clause will continue on
        if(!areValidBrackets) 
        {
            // check if left bracket but no right bracket
            if(ddlLeftBracket.SelectedIndex > 0 && ddlRightBracket.SelectedIndex == 0)
            {
                areValidBrackets = true;
                numUnclosedLeftBrackets += ddlLeftBracket.SelectedIndex;
            }
            // check if right bracket but no left bracket
            if(ddlLeftBracket.SelectedIndex == 0 && ddlRightBracket.SelectedIndex > 0)
            {
                // check if left bracket needs closing in a previous value/criteria row and make sure user is not trying to add more right closing brackets than allowed
                if(numUnclosedLeftBrackets > 0 && (numUnclosedLeftBrackets - ddlRightBracket.SelectedIndex) > -1)
                {
                    areValidBrackets = true;
                    numUnclosedLeftBrackets -= ddlRightBracket.SelectedIndex;
                }
            }
        }
    }
    else
    {
        // Since the user has not selected AND or OR, check that there are no unclosed left brackets remaining
        if(numUnclosedLeftBrackets > 0)
            areValidBrackets = false;
    }
}
if(!areValidBrackets)
    // brackets not valid
else
    if(!isValidStmt)
        // not a valid statement
    else
        if(addAnotherStmt)
            // create a new row
        else
            // finished and valid - allow saving valid 'WHERE clause' string

您可以这样做,以便启用最近的转发器行并禁用所有先前的行,从而强制用户删除每个最近的行,直到他们要编辑的行启用为止。这简化了验证,b/c 然后您只关心最近的行,知道所有先前的行都已验证。当最近的行有效时,将整个字符串作为 SQL WHERE 子句运行是安全的。

注意:如果您像我建议的那样锁定之前的行,那么当用户删除最近的行时,您将不得不检查 numUnclosedLeftBrackets 的值,这可能需要稍微不同的方法,例如:为包含未闭合左括号的每一行存储转发器行索引。

【讨论】:

  • 这可行,但有人怎么能指定(A &amp;&amp; B)||(B || C)
  • 您好,感谢您的回复,我会调查一下,看看是否可以使用它来满足我的需求。需要注意的一件小事是结果将基于网格,然后我将敲定最终结果并进行验证,以便用户可以创建一个像 (criteria = val) AND (criteria1 = val1) 这样的子句,我认为你的代码会处理这个,除了对于每行包含一个运算符的要求……这绝对不是什么大不了的事,我可以编辑和更改。再次非常感谢您的帮助!谢谢你。
  • @GartuanTezMaximus 如果我对您有所帮助,请将我的回答标记为正确。我想我知道“基于网格”是什么意思,但考虑使用中继器。我提出的解决方案完全避免了遍历整个结果以进行大规模验证,但前提是您只允许用户编辑最新行并禁用对所有先前行的编辑。
  • @BumbleB2na,我不知道该怎么做……但我也很高兴,这是一个很大的帮助。
  • @GartuanTezMaximus 很酷,谢谢 :) 如果您认为答案已回答您的问题,您可以点击答案顶部的复选标记。
【解决方案2】:

我自己偶然发现的一个解决方案,我认为它可能对其他人有用,因为我看到其他人有类似的问题......

如果您的子句的格式类似于 sql where 子句,您可以通过使用以下过程对数据库进行调用来验证它:

SET PARSE ONLY

SELECT 1
FROM sys.objects
WHERE [user generated clause]

如果通过且没有任何错误,则您有一个有效的 sql where 子句...

希望这对某人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多