ASP.NET正则表达式验证器客户端脚本错误

5
我有以下正则表达式验证器,用于检测输入字符串是否包含HTML/script标记,如果是,则会导致验证错误:
<asp:TextBox ID="txt" runat="server" />
    <asp:RegularExpressionValidator 
        ControlToValidate="txt" 
        runat="server"
        ID="regexVal"
        EnableClientScript="true"  Display="Dynamic"
        ErrorMessage="Invalid Content" 
        Text="!" 
        ValidationExpression=">(?:(?<t>[^<]*))" />

当我运行包含此标记的页面时,出现脚本错误,错误信息为“正则表达式语法错误”。 然而,当我使用System.Text.RegularExpressions中的Regex类运行相同的正则表达式时,一切都正常: 像这样:
Regex r = new Regex(">(?:(?<t>[^<]*))");
r.IsMatch(@"<b>This should cause a validation error</b>");
r.IsMatch("this is fine");

我错过了什么?

更新: 错误似乎发生在WebResource.axd中以下js函数中:

function RegularExpressionValidatorEvaluateIsValid(val) {
    var value = ValidatorGetValue(val.controltovalidate);
    if (ValidatorTrim(value).length == 0)
        return true;
    var rx = new RegExp(val.validationexpression); //this is the line causing the error
    var matches = rx.exec(value);
    return (matches != null && value == matches[0]);
}

我没有运行你的代码时遇到问题,你用的是哪个浏览器? - o.k.w
FF 3.5和IE 8。当默认浏览器设置为IE并且项目在调试模式下运行时,脚本错误将被抛出。 - Abhijeet Patel
3
我认为这是因为在客户端,正则表达式将在JavaScript中实现,因此正则表达式应符合JavaScript的正则表达式语法。由于JavaScript不支持命名捕获组,所以正则表达式应简化为>(?:([^<]*))。 - Huppie
@Huppie: 这是真的。然而 >(?:([^<]*)) 似乎也不起作用。你测试过吗? - o.k.w
EnableClientScript="true" 是默认设置。 - Marcel
5个回答

10

我认为问题在于JavaScript不理解.NET的正则表达式语法中的分组。

当您将EnableClientScript设置为true时,RegularExpressionValidator ASP.NET会重新创建您的正则表达式以在控件上启用客户端验证。在这种情况下,JavaScript不支持命名分组(?<t>...)和非捕获分组(?:...)的语法。虽然.NET中可以使用这些功能,但JavaScript却无法使用它们。

来自MSDN上的RegularExpressionValidator控件(常规参考):

在客户端上,使用JScript正则表达式语法。在服务器上,使用Regex语法。由于JScript正则表达式语法是Regex语法的子集,因此建议您使用JScript正则表达式语法,以便在客户端和服务器上产生相同的结果。

有两种方法可以纠正这个问题:

  1. 禁用客户端脚本生成,让正则表达式在服务器端执行。您可以通过将EnableClientScript设置为false来实现此目的。
  2. 修改正则表达式并删除非捕获分组和命名分组。如果您需要在正则表达式中进行捕获,(...)语法应该在JavaScript和.NET中都能正确工作。然后您可以使用序数引用来访问捕获的值($1$2等)。类似于>[^<]*的内容应该可以正常工作。请参见MSDN上的分组构造

我想指出另外几个问题:

  • 如果您只是想检查是否存在打开的尖括号,那么您原始的正则表达式似乎根本不需要捕获任何内容。它可以重写为>[^<]*,这将更简单且完全以相同的方式工作。它不会在原始字符串中捕获任何值,但由于您正在使用它在 ASP.NET 验证控件中,所以这并不重要。
  • 您实现 RegularExpressionValidator 的方式只有在匹配成功时才起作用。在您的情况下,如果文本框包含类似于 >blah 的内容,则验证通过。我认为您希望它反过来工作。
  • 如果您将正则表达式修改为>[^<]*,则正则表达式仍然无法按照我认为您想要的方式工作。验证控件尝试匹配文本框中的所有文本。因此,如果我在文本框中输入>blah,它将匹配,但是<b>blah</b>不会匹配,因为正则表达式指定字符串必须以>开头。我建议尝试类似于.*>.*[^<]*的内容,以允许在>之前输入文本。

谢谢澄清。现在这样就有意义了。我仍然想得到一个等效的正则表达式,以实现与原始正则表达式相同的最终结果,即检测HTML标记/内容,以便我可以将其标记为验证错误。有什么想法吗? - Abhijeet Patel
1
[^<>]* 可能是您的 RegularExpressionValidator 的起点。它将尝试匹配包含除了尖括号之外的任何内容的字符串。请注意,使用正则表达式解析 HTML 通常不是一个好主意:https://dev59.com/-UrSa4cB1Zd3GeqPXY9N(该问题中有很棒的链接 - 值得关注!)。在这种情况下,检测输入中的 HTML 可能是可以的... - dariom
这样做会不会将一般情况下的小于和大于符号也检测为匹配项,例如“价格必须>40且<100”? 在我处理的用例中,这样的输入被认为是有效的。只有像“<script>......</script>”或“<b>我是粗体</b>”之类的输入被视为无效。 - Abhijeet Patel
这样怎么样?^.<\w+>.$ - Abhijeet Patel
是的,我的建议的正则表达式会阻止“price < 10”等内容。我说过这只是一个开始 :-) 你想要的是可能的,但由于 RegularExpressionValidator 的工作方式很棘手(你必须反转正则表达式的逻辑 - 即指定允许哪些模式 - 而不是禁止)。你的表达式 ^.*<\w+>.*$ 不会防止输入类似 "<my tag>" 的内容。这个问题涉及到了你的 RegularExpressionValidator 控件中的错误。我建议你提出一个新问题,以找到一个合适的正则表达式模式来实现你想要的功能。 - dariom
好的,你的回答是最好的。感谢你的所有帮助。 - Abhijeet Patel

1

这对我很有帮助:

(^[^<>]*$)|(^[^>]*$)|(^[^<]*$)

我想让用户能够使用一个 < 或 > 但不是 . (尽管这在 >anything< 上失败,但我可以接受)

1

我找到了问题的根本原因,但不确定具体的解决方案。

在Firefox 3.5中使用Firebug控制台运行以下代码以触发所有客户端验证器:

for(var _v=0; _v<Page_Validators.length; _v++){
    ValidatorValidate(Page_Validators[_v]);
}

然后在txt文本框中输入一些文本,再次运行脚本,就会抛出异常:
"invalid quantifier ?[^<]*))"

不知何故,浏览器的正则表达式引擎无法解析该正则表达式字符串。我还没有找到其替代正则表达式。


我在想这是否是ASP.NET在发出正则表达式的JavaScript时出现了错误,就像我在更新中提到的那样,以下行会失败: var rx = new RegExp(val.validationexpression); - Abhijeet Patel
我建议更换为替代的正则表达式或仅使用服务器端验证。我也遇到了一些浏览器的正则表达式兼容性问题。 - o.k.w

0

你应该尝试这个正则表达式 Regex r = new Regex(@">(?:(?[^<]*))");


0

感谢dariom...这似乎很简洁并且有效... [RegularExpression(@"[^<>]*", ErrorMessage = "请不要使用SCRIPT标签。")]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接