本篇要讲述的知识点如下:
数据验证介绍
纯客户端脚本验证
asp.net验证控件概述
RequiredFieldValidator控件
CompareValidator控件
RangeValidator控件
正则表达式
RegularExpressionValidator控件
CustomValidator控件
ValidationSummary控件
分组校验技术
数据验证介绍
在我们的开发中要提高网站的健壮性,为了做到这些笔者曾经在企业培训时候提到了两个原则:
第一条原则:就是尽量减少让用户输入的机会,比如数据的录入时间我们可以设置该条记录的为数据库的当前时间,这个可以在创建或者设计表的时候实现。下面就是一个例子:
- create table ActionLog (
- LogID bigint identity(1,1),
- UserID int not null,
- UserIP varchar(15) not null,
- ActionDate datetime null default getdate(),
- ActionDescription nvarchar(800) not null,
- ActionStatus tinyint not null,
- WebSiteID int not null,
- constraint PK_ACTIONLOG primary key (LogID)
- )
- Go
上面中的ActionDate字段就是设置成自动获取数据库服务器当前时间,这样在插入记录的时候无需在这个字段插入值。如果这个值让用户填写一来可能用户不能按照我们要求的格式填写,二来即使按照我们的要求填写也可能用户不会填写当前时间,如果采用上面的办法就能有效避免这个问题。
第二条原则:就是不要过分相信用户一定会按照我们的要求规规矩矩去做。最终使用我们的软件产品的用户大都计算机水平不高(如果水平高可能就会自己开发了),所以他们可能不太懂得什么格式和要求之类的,这就经常需要对用户填写的数据进行检查。如果我们对用户提交的数据经过充分检查,那么就能有效提高程序的健壮性,这样也能从某些途径堵住了黑客入侵我们系统的路子。
对数据的检查按时机来分可以分为客户端检查和服务器端检查。
在客户端检查是指通过客户端脚本(如javascript脚本或者vbscript脚本)来进行检查,利用客户端脚本检查的好处是减小网络流量、减轻服务器压力和反映迅速。因为客户端脚本是在客户端运行,我们可以定义好检验规则,在客户端就可以完成检验,一旦不能通过验证客户端马上就能得到提示,而不用将整个表单提交到服务器(笔者早些年曾经就有这样的经历:网速28.8K的情况下提交一个注册表单,数分钟后得到服务器的反馈说是用户名不符合要求,当时差点吐血),用户体验非常好。客户端验证也有一些缺点:因为我们的验证规则完全定义在客户端脚本中,不怀好意的窥探者可以从这些客户端代码找出我们脚本的漏洞或者某些跳过脚本验证的方法,从而造成网站的健壮性出现问题,这就对客户端代码的客户端脚本编程能力提出了挑战。另外客户端验证可能会使我们写得非常优秀的代码在短短几天流传整个网络,不能进行版权控制。
在服务器端检查是指将表单提交到服务器后在服务器上用服务器端代码进行验证(如用C#或者VB.NET等),服务器端验证的优点是我们的验证规则对用户来说是一个黑匣子,比较难找出我们验证代码的漏洞,并且服务器端验证的代码编写起来相对客户端脚本要容易得多,但是服务器端验证也有缺点:那就是大量的复杂验证会降低服务器的性能。
因此一般验证办法都是上面两种样式结合,利用客户端验证建立验证的第一道关卡,这个关卡将大量无意中填写的不符合要求的数据阻止在客户端,然后在服务器端建立第二道关卡,将那些利用了我们的客户端脚本漏洞的数据阻止在保存之前。
客户端脚本验证
下面是一个利用客户端脚本在客户端进行验证的例子。我们对Button服务器控件的OnClientClick加上一个客户端验证方法,只有当这个客户端方法返回true的时候表单才会向服务器提交,如果用户填写的数据不符合要求就返回false值。
下面是前台代码(后台没有编写任何代码):
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ClientValidate.aspx.cs" Inherits="ClientValidate" %>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>纯客户端脚本验证的例子title>
- <script language="javascript" type="text/javascript">
- //当这个方法返回false的情况下就不会向服务器提交数据
- function checkForm()
- {
- //如果没有填写任何数据
- if(document.form1.txtUserName.value=="")
- {
- alert("用户名不能为空!");
- return false;
- }
- var length=document.form1.txtUserName.value.length;
- //如果填写内容长度不在6到10字符之间
- if(length<6||length>10)
- {
- alert("用户名必须是6到10个字符!");
- return false;
- }
- else
- {
- return true;
- }
- }
- script>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="0">
- <tr><td>用户名td><td><asp:TextBox ID="txtUserName" runat="server">asp:TextBox>td>tr>
- <tr><td><asp:Button ID="btnOK" runat="server" Text="提交" OnClientClick="javascript:return checkForm();" OnClick="btnOK_Click" />td><td><input type="reset" value="清空" />td>tr>
- table>
-
- div>
- form>
- body>
- html>
运行效果如下:
如果用户没有填写任何数据就提交表单会得到如下提示:
如果我们填写的字符个数不是6到10个之间提交表单会看到如下效果:
通过上面的例子展示了如何在asp.net中如何利用客户端脚本对表单进行验证,经过上面的大家也能感觉得到用客户端脚本对表单进行验证的编码特点:可以灵活控制验证方法,但是编写客户端脚本比较麻烦,调试起来也不太容易,在目前还没有一款比较好的javascript脚本编写和调试的软件。为了提高开发asp.net网站的速度,微软提供了一套asp.net的验证控件。
asp.net验证控件概述
所有的asp.net验证控件都直接或者间接派生自BaseValidator这个抽象类,BaseValidator类定义了验证控件的一些共有属性和方法。验证控件用于验证与其关联的输入控件的值,当用户的输入不能通过验证时,将会显示预定义的错误提示信息。验证控件的位置并没有规定,可以在页面的任意位置放置验证控件,但是一般为了直观起见,尽量将验证控件靠近要验证的控件的位置。asp.net验证控件可以对以下类型的asp.net控件的值进行验证:
控件名 |
要验证的属性 |
备注 |
DropDownList |
SelectedValue |
验证选中项的值 |
FileUpload |
FileName |
验证要上传的文件名 |
ListBox |
SelectedItem.Value |
验证选中的第一项的值 |
RadioButtonList |
SelectedItem.Value |
验证选中项的值 |
TextBox |
Text |
验证文本框的值 |
HtmlInputFile |
Value |
验证HTML服务器上传控件中的文件名 |
HtmlInputPassword |
Value |
验证HTML服务器文本控件的值 |
HtmlInputText |
Value |
验证HTML服务器文本控件的值 |
HtmlSelect |
Value |
验证HTML服务器下拉控件选中的值 |
HtmlTextArea |
Value |
验证HTML服务器多行文本控件的值 |
从上表中我们可以看出验证控件验证的控件类型只能是asp.net服务器控件和HTML服务器控件,而不能验证普通HTML控件,如果要普通HTML控件进行验证,只能像笔者在上一个例子中演示的那样自己编写客户端脚本代码进行验证。
在默认情况下,asp.net服务器控件将首先在客户端进行验证,然后再发送到服务器端进行验证,当然也可以设置它的EnableClientScript属性来指定是否需要在客户端进行验证。BaseValidator类有如下常见属性:
属性名 |
说明 |
ControlToValidate |
待验证的控件的ID |
Display |
错误信息的显示方式,有None、Static和Dynamic,默认为Static |
EnableClientScript |
是否启用客户端验证 |
Enabled |
是否启用验证控件 |
ErrorMessage |
验证失败时显示的信息 |
IsValid |
关联的控件是否通过验证 |
SetFocusOnError |
当验证失败时是否将焦点移动到关联的控件上 |
Text |
验证失败时在验证控件中要显示的信息 |
ValidationGroup |
验证控件所在的分组名 |
对上面几个属性做一点说明:
(1)Display属性是决定如何显示错误消息的,默认是Static,即始终为错误信息分配显示空间,Dynamic方式是只在需要的时候才为错误信息分配显示空间,而None方式是将错误信息集中到ValidationSummary控件中显示。
(2)ErrorMessage属性是待验证控件不能通过验证的时候在ValidationSummary控件中显示要显示的信息,Text属性是待验证控件不能通过验证是在验证控件中显示的信息,如果只设置了ErrorMessage属性而没有设置Text属性并且Display方式不为None时将会显示ErrorMessage属性的值。
(3)ControlToValidate是必须指定的,否则在运行的时候将会报错。
RequiredFieldValidator控件
RequiredFieldValidator控件也被称之为必填验证控件,顾名思义,也就是与RequiredFieldValidator控件关联的控件的值在默认设置下必须填写。笔者在这里用了个限定词“在默认设置下”,是因为RequiredFieldValidator控件除了BaseValidator中定义的属性之外,还有一个比较重要的属性:InitialValue。默认情况下这个属性的值是String.Empty,如果控件的值与它的默认值一致就不能通过验证,即如果关联的控件没有填写的话就不能通过验证,在验证DropDownList控件的时候我们也可以使用RequiredFieldValidator控件,不过需要设置RequiredFieldValidator控件的InitialValue属性。
下面我们通过一个例子来演示RequiredFieldValidator控件如何验证TextBox控件和DropDownList控件。在程序中我们给DropDownList控件添加了一个默认选项“请选择”,一旦用户没有改变DropDownList控件的选中值就不能通过验证。
在设置验证控件的关联控件时,验证控件会自动找出当前页面中哪些控件是可以进行验证的,如下图:
注意:在上图中控件ID不是TextBox1或者DropDownList这种默认形式,是因为我更改了其默认ID。在实际开发中我一般会更改控件的默认ID,用一个比较直观的ID,这样便于我们在代码中操作。我对服务器控件的ID命名一般遵循控件类型前缀加控件用户的办法,下面举例说明:
控件类型 |
前缀 |
举例 |
TextBox |
txt |
txtUserName |
Label |
lb |
lbServerTime |
DropDownList |
ddl |
ddlState |
Literal |
l |
lTitle |
Button |
btn |
btnOK |
RadioButton |
rb |
rbMale |
CheckBox |
cb |
cbApply |
这样的做法比整个页面一堆Button1、Button2及TextBox1、TextBox2强得多,基本上能做到望文知义。
因为只是演示验证控件的验证效果,所以没有什么后台代码,采用了单页模式。下面是实例代码:
- <%@ Page Language="C#" %>
- <script runat="server">
- script>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>RequiredFieldValidator控件用法的例子title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="400">
- <tr><td>用户名td><td>
- <asp:TextBox ID="txtUserName" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtUserName"
- ErrorMessage="用户名必须填写">asp:RequiredFieldValidator>td>tr>
- <tr><td>省份td><td>
- <asp:DropDownList ID="ddlState" runat="server">
- <asp:ListItem Selected="True">请选择asp:ListItem>
- <asp:ListItem Value="1">湖北asp:ListItem>
- <asp:ListItem Value="2">湖南asp:ListItem>
- <asp:ListItem Value="3">山东asp:ListItem>
- <asp:ListItem Value="4">山西asp:ListItem>
- <asp:ListItem Value="5">河南asp:ListItem>
- <asp:ListItem Value="6">河北asp:ListItem>
- asp:DropDownList>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="ddlState"
- ErrorMessage="请选择省或者直辖市" InitialValue="请选择">asp:RequiredFieldValidator>td>tr>
- <tr><td>
- <asp:Button ID="btnOK" runat="server" Text="提交" />
- td><td>
-
- <input id="Reset1" type="reset" value="reset" />td>tr>
- table>
- div>
- form>
- body>
- html>
下面是运行效果:
当我们直接点击“提交”之后的效果:
一旦我们填写了用户名,并且选择一个省份而不是让“请选择”处于选中状态,那么这个表单就能提交到服务器进行处理了。在这个例子里我们没有写一行客户端脚本代码。
CompareValidator控件
CompareValidator控件也被称之为比较验证控件,它是用来验证两个控件的值或者控件与某个值之间的关系,除了在BaseValidator中定义的属性之外,CompareValidator控件还定义了如下属性:
属性名 |
说明 |
ControlToCompare |
要与所验证的输入控件进行比较的输入控件的ID |
Operator |
要执行的比较操作 |
Type |
对控件的值按照哪种方式进行比较,默认String |
ValueToCompare |
设置要与所验证的控件的值进行比较的值 |
说明:因为在输入控件中可以输入货币、浮点数、整数及字符串等,所以需要设置控件的值按照什么类型的值进行验证,可以进行验证的类型有如下:
类型 |
说明 |
Currency |
按货币类型比较,小数点后最多两位数字 |
Date |
按日期类型比较(不带时分秒) |
Double |
按浮点数类型比较 |
Integer |
按整数类型比较 |
String |
按字符串类型比较 |
在进行验证的时候还可以指定两个值之间满足什么关系不能通过验证,这个关系可以通过设置Operator属性来指示,分别有<(LessThan)、<=(LessThanEqual)、!= (NotEqual)、=(Equal)、>(GreaterThan)及>=(GreaterThanEqual)。
另外有时候我们可能不是将两个控件的值进行比较,而是将所验证的控件的值与某个指定的值进行比较,那么可以不设置ControlToCompare属性的值而设置ValueToCompare属性的值,验证的时候将用ValueToCompare属性的值与所验证的控件的值按照Type属性指定的类型和Operator属性定义的比较操作来进行验证。
注意:请不要同时设置ControlToCompare属性和ValueToCompare属性,如果同时指定了这两个属性,则ValueToCompare属性优先。
CompareValidator控件用得比较多的场合就是用于确保用户在注册时两次输入的密码一致,还有在某些场合下有一定先后顺序的日期数据,比如某个事件的开始日期和结束日期。
经常看香港警匪片的朋友一定会对警察抓捕嫌疑犯时经常说的那句“你有权保持沉默,但是你所说的将来会成为呈堂证供”不陌生,在asp.net中除了RequiredFieldValidator控件之外,CompareValidator控件、RangeValidator控件和RegularExpressionValidator控件对待所验证的控件也是持这种态度:所验证的控件如果没有任何输入也是能通过验证的,但是如果输入的数据不符合验证规则就不能通过验证!要是要求用户必须输入并且还要符合一定规则,上述的控件就需要结合RequiredFieldValidator控件共同验证。
在下面的例子中要用户填写一个旅游申请,要填写的数据有旅游出发时间、旅游人数、旅游经费及旅游结束时间。根据业务规则,在这个表单中有如下要求:
(1)出发时间一定早于结束时间。
(2)旅游人数一定要大于0(一个人都不参加这个旅游就没有意义了)。
(3)旅游经费可以不填写(难以估算),但一旦填写就必须填写大于0.00的金额。
在这里所有的验证都是用CompareValidator控件结合RequiredFieldValidator控件来进行验证,RequiredFieldValidator控件验证所验证的控件是否填写了数据,CompareValidator控件负责进行比较验证,代码如下:
- <%@ Page Language="C#" %>
- <script runat="server">
- script>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>CompareValidator灵活使用的例子title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">旅游活动申请表td>tr>
- <tr><td>
- 开始时间td><td>
- <asp:TextBox ID="txtStartDate" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtStartDate"
- ErrorMessage="用户名必须填写">asp:RequiredFieldValidator>
- <asp:CompareValidator ID="CompareValidator1" runat="server" ErrorMessage="开始日期必须早于结束日期" ControlToCompare="txtStartDate" ControlToValidate="txtEndDate" Operator="GreaterThanEqual" Type="Date">asp:CompareValidator>td>tr>
- <tr><td>
- 结束时间td><td>
- <asp:TextBox ID="txtEndDate" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtEndDate"
- ErrorMessage="请填写结束时间">asp:RequiredFieldValidator>
- td>tr>
- <tr><td>
- 参加人数td><td>
- <asp:TextBox ID="txtNumber" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txtNumber"
- ErrorMessage="必须填写人数">asp:RequiredFieldValidator>
- <asp:CompareValidator ID="CompareValidator2" runat="server" ControlToValidate="txtNumber"
- ErrorMessage="人数必须大于0" Operator="GreaterThan" Type="Integer" ValueToCompare="0">asp:CompareValidator>td>tr>
- <tr><td>
- 经费预算td><td>
- <asp:TextBox ID="txtMoney" runat="server">asp:TextBox>
- <asp:CompareValidator ID="CompareValidator3" runat="server" ControlToValidate="txtMoney"
- ErrorMessage="经费必须是大于0的数字" Type="Currency" ValueToCompare="0" Operator="GreaterThan">asp:CompareValidator>td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- form>
- body>
- html>
下面不填写任何信息提交表单的效果:
从上图我们可以得出一个结论:因为经费预算只使用了CompareValidator控件,所以如果用户不填写任何信息是能够通过验证的。
现在我们填写表单,这里故意将结束时间设置得比开始时间早,并且在参加人数中填写了一个“q”,下面是提交表单的效果:
从上面的效果我们可以得出下面的结论:
(1)如果填写数据不能按照期望的数据类型进行转换时是不能通过验证的,因为我们期望用户在参加人数一栏填写大于0的数字,用户填写了英文字母所以不能通过验证。同理,如果用户在经费预算一栏中填写了不能转换成货币的数字(即小数点后最多两位数字的浮点数)、在开始时间或者结束时间填写了不能转换成日期的数据都是不能通过验证的。
(2)验证控件的Display属性默认为Static,在这种情况下即使所验证的控件通过了验证,但是页面仍然为其分配了显示控件,比如用于验证开始时间、结束时间和参加人数的RequiredFieldValidator控件,虽然满足了必须填写的要求,可是因为它们的属性都是static的,所以当不能通过CompareValidator控件的验证时,CompareValidator控件的错误提示信息仍然与文本框保持了一段距离。
现在我们把页面上所有验证的Display的属性设置为Dynamic,也就是仅在必要的时候页面才为其分配显示空间,因为Display属性是所有验证控件所共有的属性,所以我们可以按住Ctrl键的同时用鼠标选取所有的验证控件,然后集中设置所有控件的Display属性,如下图:
我们重新运行页面,填写和上次一样的信息,然后提交表单,这次的错误提示信息与文本框之间的距离就没有刚才那么明显了,效果如下:
这是如果我们将开始时间和结束时间的值互换,并且在参加人数一栏填写大于0的整数时就能提交表单到服务器进行处理。
提示:其实所有的错误信息都是通过方式输出的,当验证控件的Display属性为Static时输出的span格式是“”这样的形式,当Display属性为Dynamic时输出的span格式是“”这样的形式。
RangeValidator控件
RangeValidator控件也称之为范围验证控件,也就是只有当用户填写的非空数据不在指定的范围之间时就不能通过验证。除了具有BaseValidator所有的属性之外,它还具有如下常见属性:
属性名 |
说明 |
MaximumValue |
允许的最大值 |
MinimumValue |
允许的最小值 |
Operator |
要执行的比较操作 |
Type |
对控件的值按照哪种方式进行比较,默认String |
下面是一个RangeValidator控件的例子。比如在实际中开发一个婚恋网站,里面有一栏是填写用户生日的,有一栏是用户填写生日信息的,因为婚恋网站是针对成年人的,所以我们可以根据用户填写的生日来确保用户填写表单时年龄在18岁至100岁之间(不要告诉我超过了100岁的人还搞婚恋,I服了U),如果未超过18岁则不能注册,这个时间是根据用户填写表单的时间进行判断的,所以我们没有直接给RangeValidator控件赋最大值和最小值,而是在页面运行获取当前服务器时间,用户所能填写的生日必须当前日期之前100年至18年之间,这样就保证了用户在注册时年龄在18岁至100之间。下面是代码:
- <%@ Page Language="C#" %>
- <script runat="server">
- protected void Page_Load(object sender, EventArgs e)
- {
- //注意因为是需要根据填写表单的日期动态判断
- //所以在这里动态给RangeValidator赋最大值和最小值
- DateTime minimumValue=DateTime.Now.AddYears(-100);
- DateTime maximumValue = DateTime.Now.AddYears(-18);
- RangeValidator1.MinimumValue = minimumValue.ToString("yyyy-MM-dd");
- RangeValidator1.MaximumValue =maximumValue.ToString("yyyy-MM-dd") ;
- }
- script>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>RangeValidator控件验证的例子title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">
- 周公婚恋交友网td>tr>
- <tr><td>
- 生日td><td>
- <asp:TextBox ID="txtBirthday" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtBirthday"
- ErrorMessage="生日必须填写" Display="Dynamic">asp:RequiredFieldValidator>
- <asp:RangeValidator ID="RangeValidator1" runat="server" Display="Dynamic" ErrorMessage="你的年龄不能注册"
- MaximumValue="" MinimumValue="" Type="Date" ControlToValidate="txtBirthday">asp:RangeValidator>td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- form>
- body>
- html>
下面是运行结果:
正则表达式
正则表达式提供了功能强大、灵活而又高效的方法来处理文本。正则表达式的全面模式匹配表示法使您可以快速分析大量文本以找到特定的字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合以生成报告。对于处理字符串(例如 HTML 处理、日志文件分析和 HTTP 标头分析)的许多应用程序而言,正则表达式是不可缺少的工具。正则表达式是一个非常有用的技术,有人曾称之为能让程序员不至于丢掉饭碗的十大技术之一,可见它的重要性。完全详细讲述正则表达式的用法可能需要厚厚一本书(我也曾经见过一本厚厚的讲述正则表达式的英文书),但是在本系列课程里限于篇幅只能做一个简单的介绍,有兴趣的朋友可以参考其它书籍。
熟悉DOS或者命令行的朋友或许已经用过类似的功能,比如我们要查找某个文件夹下所有的低于Word2007版本的Word文件(因为低于Word2007版本的Word文件的文件后缀是.doc,而Word2007版本的Word文件的文件后缀是.docx),我们可以在命令行下执行这个命名:dir *doc,下面是在笔者的电脑上执行的结果:
在“dir *doc”中,*就是表示任何字符的意思。
正则表达式语言由两种基本字符类型组成:原义(正常)文本字符和元字符。元字符使正则表达式具有处理能力。下面是一些常见的元字符:
元字符 |
说明 |
. |
匹配除 /n 以外的任何字符。 |
[abcde] |
匹配abcde之中的任意一个字符 |
[a-h] |
匹配a到h之间的任意一个字符 |
[^fgh] |
不与fgh之中的任意一个字符匹配 |
/w |
匹配大小写英文字符及数字0到9之间的任意一个,相当于[a-zA-Z0-9] |
/W |
不匹配大小写英文字符及数字0到9之间的任意一个,相当于[^a-zA-Z0-9] |
/s |
匹配任何空白字符,相当于[ /f/n/r/t/v] |
/S |
匹配任何非空白字符,相当于[^/s] |
/d |
匹配任何0到9之间的单个数字,相当于[0-9] |
/D |
不匹配任何0到9之间的单个数字,相当于[^0-9] |
上面的元字符都是针对单个字符匹配的,要想同时匹配多个字符的话,还需要借助限定符。下面是一些常见的限定符(下表中n和m都是表示整数):
限定浮 |
说明 |
* |
匹配0到多个元字符,相当于{0,} |
? |
匹配0到1个元字符,相当于{0,1} |
{n} |
匹配n个元字符 |
{n,} |
匹配至少n个元字符 |
{n,m} |
匹配n到m个元字符 |
+ |
匹配至少1个元字符,相当于{1,} |
^ |
字符串必须以指定的字符开始 |
$ |
字符串必须以指定的字符结束 |
说明:
(1)由于在正则表达式中“/”、“?”、“*”等字符已经具有一定特殊意义,如果需要用它们的原始意义,则应该对它进行转义,例如希望在字符串中至少有一个“/”,那么正则表达式应该这么写://+。
(2)可以将多个元字符或者原义文本字符用括号括起来形成一个新的元字符,比如^(13)[0-9]/d{8}$表示任意以13开头的手机号码。
(3)另外对于中文字符的匹配是采用其对应的Unicode编码来匹配的,对于单个Unicode字符,如/u4e00表示汉字“一”, /u9fa5表示汉字“龥”,在Unicode编码中这分别是所能表示的汉字的第一个和最后一个的Unicode编码,在Unicode编码中能表示20901个汉字。
不要认为我记性好,我是从来不记这个的,每次用的时候我都会写一个小程序,查看其运行结果就行了。下面是我这个程序的代码:
- using System;
- using System.IO;
- public class UnicodeDemo
- {
- public static void Main()
- {
- using (StreamWriter writer = new StreamWriter(new FileStream("Unicode.txt", FileMode.Create)))
- {
- int value = 0;
-
- for (char c = char.MinValue; c <= char.MaxValue; c++)
- {
- value = (int)c;
-
-
-
- writer.WriteLine("{0}=//u{1}={2}", value,value.ToString("x"), c);
- }
- }
- }
- }
将代码编译生成Windows下的控制台程序,运行会在上面会抛出异常,因为有些字符在笔者所使用的编码范围中无法表示,不过这不影响我们查看汉字的范围。最后生成的文件内容如下:
因为汉族的人名最少两个汉字(比如张三),最多四个汉字(比如东方不败),所以匹配汉族的人名可以用这样的形式:[/u4e00-/u9fa5]{2,4}。
RegularExpressionValidator控件
RegularExpressionValidator控件就是利用正则表达式来验证其它控件的值的控件。除了具有BaseValidator所有的属性之外,它还具有一个常见属性:ValidationExpression。这个属性就是用来设置用于匹配所要验证控件的值的正则表达式。
RegularExpressionValidator控件提供了一个正则表达式编辑器,内置了一些常见的正则表达式,当我们在属性窗口设置RegularExpressionValidator控件时会看到如下效果:
点击ValidationExpression一栏右边的省略号会出现如下界面:
如果时一些常用的正则验证,可以使用使用提供标准表达式。
下面是RegularExpressionValidator控件用法的例子:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="RegularExpressionValidatorDemo.aspx.cs" Inherits="RegularExpressionValidatorDemo" %>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>RegularExpressionValidator控件的例子title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">
- 周公婚恋交友网td>tr>
- <tr><td>
- 真实姓名td><td>
- <asp:TextBox ID="txtUserName" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtUserName"
- ErrorMessage="姓名必须填写" Display="Dynamic">asp:RequiredFieldValidator>
- <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ErrorMessage="姓名是2到4个汉字" ControlToValidate="txtUserName" Display="Dynamic" ValidationExpression="[/u4e00-/u9fa5]{2,4}">asp:RegularExpressionValidator>td>tr>
- <tr><td>
- 手机号td><td>
- <asp:TextBox ID="txtMobile" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtMobile"
- ErrorMessage="姓名必须填写" Display="Dynamic">asp:RequiredFieldValidator>
- <asp:RegularExpressionValidator ID="RegularExpressionValidator2" runat="server" ControlToValidate="txtMobile"
- ErrorMessage="不正确的手机号" ValidationExpression="((13[0-9])|(15[89]))/d{8}">asp:RegularExpressionValidator>td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- form>
- body>
- html>
在例子中要求真实姓名必须是2到4个汉字,手机号必须是13开头或者是158、159开头的并且总长度是11位数字。以下是运行效果:
CustomValidator控件
CustomValidator控件也成为自定义验证控件,通过RequiredFieldValidator控件结合CompareValidator控件、RangeValidator控件或RegularExpressionValidator控件之中的一个或多个就能满足asp.net开发中的90%以上的验证要求,但是有一些特殊的验证用上述控件组合无法达到验证要求,比如要求用户填写一个奇数。为了满足一些特殊的验证要求,在asp.net中还有一个CustomValidator控件,在这个控件中可以自己写验证规则。
CustomValidator类是BaseValidator抽象类,所以CustomValidator控件拥有BaseValidator中定义的属性,除此之外,CustomValidator控件还有以下常见属性:
属性名 |
说明 |
ClientValidationFunction |
用于在客户端执行验证的客户端函数名 |
ValidateEmptyText |
是否验证空文本,即当所验证控件值为空时时候执行客户端验证 |
CustomValidator控件用于在客户端验证的函数有两个参数,第一个是表示被验证的控件,第二个表示事件数据。第二个参数有两个属性:IsValid用于表示被验证控件是否通过验证,Value属性表示被验证的控件的值。下面就是一个客户端验证函数的例子:
除了客户端验证之外,在CustomValidator控件中还能自己写服务器端写验证方法,它有一个OnServerValidate事件,同它的客户端处理函数一样,处理这个事件的委托也需要两个参数,第一个是表示被验证的控件,第二个表示事件数据。第二个参数有两个属性:IsValid用于表示被验证控件是否通过验证,Value属性表示被验证的控件的值。它服务器端验证方法设置界面如下:
下面我们用一个例子来说明CustomValidator控件的用法,在这里例子里用户被要求输入两个数,一个必须是2的倍数,一个必须是3的倍数。用CustomValidator控件就能很轻松完成这个功能。
下面是前台代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CustomValidatorDemo.aspx.cs" Inherits="CustomValidatorDemo" %>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>CustomValidator验证控件用法的例子title>
- <script language="javascript" type="text/javascript">
- //obj表示被验证的控件
- //args表示事件数据,args有两个属性
- //IsValid指示控件是否通过验证
- //Value表示被验证的控件的值
- function CheckEven(obj,args)
- {
- var numberPattern=//d+/;
- //由于控件的ValidateEmptyText设置为true
- //所以当控件没有值时进行客户端验证
- if(!numberPattern.test(args.Value))
- {
- args.IsValid=false;//表示未通过验证,出现错误提示
- }
- else if(args.Value%2==0)
- {
- args.IsValid=true;//表示通过验证,不出现错误提示
- }
- else
- {
- args.IsValid=false;//表示未通过验证,出现错误提示
- }
- }
-
- function CheckMultiple3(obj,args)
- {
- //由于控件的ValidateEmptyText没有设置,使用了默认值false
- //所以当控件没有值时不进行客户端验证
- var numberPattern=//d+/;
- if((!numberPattern.test(args.Value))||(args.Value%3!=0))
- {
- args.IsValid=false;
- }
- else
- {
- args.IsValid=true;
- }
- }
- script>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">CustomValidator验证控件用法的例子td>tr>
- <tr><td>
- 填一个3的倍数td><td>
- <asp:TextBox ID="txtOdd" runat="server">asp:TextBox>
- <asp:CustomValidator ID="CustomValidator2" runat="server" ControlToValidate="txtOdd"
- ErrorMessage="请输入3的倍数" ClientValidationFunction="CheckMultiple3" Display="Dynamic" OnServerValidate="CustomValidator2_ServerValidate">asp:CustomValidator>td>tr>
- <tr><td>
- 填一个偶数td><td>
- <asp:TextBox ID="txtEven" runat="server">asp:TextBox>
- <asp:CustomValidator ID="CustomValidator1" runat="server" ControlToValidate="txtEven"
- ErrorMessage="请输入偶数" ClientValidationFunction="CheckEven" ValidateEmptyText="True" OnServerValidate="CustomValidator1_ServerValidate">asp:CustomValidator>td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- form>
- body>
- html>
此外,还编写了服务器端验证方法,下面是后台代码:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
- public partial class CustomValidatorDemo : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
-
- protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
- {
- System.Text.RegularExpressions.Regex regex=new System.Text.RegularExpressions.Regex("//d+");
-
- if (!regex.IsMatch(args.Value))
- {
- args.IsValid = false;
- }
- else
- {
-
- args.IsValid = (int.Parse(args.Value) % 3 == 0);
- }
- }
-
- protected void CustomValidator2_ServerValidate(object source, ServerValidateEventArgs args)
- {
- System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("//d+");
-
- if (regex.IsMatch(args.Value))
- {
- args.IsValid = false;
- }
- else
- {
-
- args.IsValid=(int.Parse(args.Value) % 2 == 0);
- }
- }
-
- }
以下是什么也不填写时的验证效果:
在上图中,由于验证奇偶性的CustomValidator验证控件设置了ValidateEmptyText属性为true,所以即使所验证的控件是空值时也会执行客户端验证。从这个例子中可以看出CustomValidator验证控件可以不需要RequiredFieldValidator控件就能实现必填验证,只要将它的ValidateEmptyText属性设为true即可。
ValidationSummary控件
ValidationSummary控件是用于显示验证所有验证错误摘要的控件,当我们将验证控件的Display属性设置None的时候,验证错误信息就在这里显示。
ValidationSummary控件有三个常见属性:
属性名 |
说明 |
DisplayMode |
指定显示模式,有BulletList、List、SingleParagraph三种模式 |
ShowMessageBox |
是否以客户端提示框的信息显示验证错误信息摘要 |
ShowSummary |
是否在网页中采用内联方式显示错误摘要 |
下面是一个ValidationSummary控件的例子(在使用ValidationSummary控件的时候一定要将验证控件的Display属性设为None):
- <%@ Page Language="C#" %>
- <script runat="server">
- script>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>ValidationSummary控件的例子title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">旅游活动申请表td>tr>
- <tr><td>
- 开始时间td><td>
- <asp:TextBox ID="txtStartDate" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtStartDate"
- ErrorMessage="用户名必须填写" Display="None">asp:RequiredFieldValidator>
- <asp:CompareValidator ID="CompareValidator1" runat="server" ErrorMessage="开始日期必须早于结束日期" ControlToCompare="txtStartDate" ControlToValidate="txtEndDate" Operator="GreaterThanEqual" Type="Date" Display="None">asp:CompareValidator>td>tr>
- <tr><td>
- 结束时间td><td>
- <asp:TextBox ID="txtEndDate" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtEndDate"
- ErrorMessage="请填写结束时间" Display="None">asp:RequiredFieldValidator>
- td>tr>
- <tr><td>
- 参加人数td><td>
- <asp:TextBox ID="txtNumber" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txtNumber"
- ErrorMessage="必须填写人数" Display="None">asp:RequiredFieldValidator>
- <asp:CompareValidator ID="CompareValidator2" runat="server" ControlToValidate="txtNumber"
- ErrorMessage="人数必须大于0" Operator="GreaterThan" Type="Integer" ValueToCompare="0" Display="None">asp:CompareValidator>td>tr>
- <tr><td>
- 经费预算td><td>
- <asp:TextBox ID="txtMoney" runat="server">asp:TextBox>
- <asp:CompareValidator ID="CompareValidator3" runat="server" ControlToValidate="txtMoney"
- ErrorMessage="经费必须是大于0的数字" Type="Currency" ValueToCompare="0" Display="None" Operator="GreaterThan">asp:CompareValidator>td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- <asp:ValidationSummary ID="ValidationSummary1" runat="server" DisplayMode="SingleParagraph"
- ShowSummary="False" />
- form>
- body>
- html>
在上面的例子中ValidationSummary控件的ShowMessageBox属性采用了默认值false,并且ShowSummary采用了默认属性true,以下是什么也不填写时提交表单的效果:
如果我们将上面的例子中的ValidationSummary控件的ShowMessageBox属性设为true并且ShowSummary属性设置为false,提交空表单时会得到如下效果:
分组校验技术
分组验证技术有助于我们分成组进行验证,默认情况下我们没有设置验证控件的ValidationGroup属性,那么这些没有设置ValidationGroup属性的将会算做一个默认分组进行验证。我们看下面的一个例子:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Register.aspx.cs" Inherits="Register" %>
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>无标题页title>
- head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table border="1" width="600">
- <tr><td colspan="2" align="center">
- 用户注册td>tr>
- <tr><td>
- 用户名td><td>
- <asp:TextBox ID="txtUserName" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtUserName"
- ErrorMessage="用户名必须填写" Display="Dynamic">asp:RequiredFieldValidator>
- td>tr>
- <tr><td>
- 密码td><td>
- <asp:TextBox ID="txtPassword" runat="server">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtPassword"
- ErrorMessage="必须填写密码" Display="Dynamic">asp:RequiredFieldValidator>
- td>tr>
- <tr><td>
- 用户头像td><td>
- <asp:TextBox ID="txtHeadImage" runat="server" onfocus="blur();">asp:TextBox>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txtHeadImage"
- ErrorMessage="必须上传头像" Display="Dynamic">asp:RequiredFieldValidator>
- <asp:FileUpload ID="FileUpload1" runat="server" />
- <asp:Button ID="btnUpload" runat="server" Text="上传" />
- <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" ControlToValidate="FileUpload1"
- Display="Dynamic" ErrorMessage="必须选择文件">asp:RequiredFieldValidator>
- td>tr>
- <tr><td>
- <asp:Button ID="Button2" runat="server" Text="提交" />
- td><td>
- <input id="Reset3" type="reset" value="重置" />td>tr>
- table>
- div>
- form>
- body>
- html>
它的后台代码如下:
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
- public partial class Register : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
- protected void btnUpload_Click(object sender, EventArgs e)
- {
-
- if (fileUpload.HasFile)
- {
-
- string savePath = Server.MapPath("~/upload/");
-
- if (!System.IO.Directory.Exists(savePath))
- {
-
-
- System.IO.Directory.CreateDirectory(savePath);
- }
- savePath = savePath + "//" + fileUpload.FileName;
- fileUpload.SaveAs(savePath);
-
- txtHeadImage.Text = string.Format("upload/{0}", fileUpload.FileName);
- }
- }
- }
注意在页面中笔者使用了javascript技术让头像文本框无法输入,只能在用户上传头像成功之后才会自动设置成用户上传成功后头像URL地址。
这个页面的运行效果如下:
在这个页面中这个页面是很难按照正常方式注册成功的,因为要想上传头像成功则必须表单中所有字段都填写了,而用户头像一栏又是必须用户上传头像成功之后自动成为上传的头像在服务器端的URL地址的。当我们选择一个本地头像点“上传”按钮时的效果:
同样点“提交”按钮也不能上传成功。这种情况下我们就可以使用分组技术,将验证上传控件的验证控件和上传按钮的ValidationGroup属性设为同一个值(按住Ctrl键同时选择上述两个控件),如下图:
这样点“上传”按钮的时候只有ValidationGroup属性与该按钮的ValidationGroup属性一致的按钮才会验证所关联的控件的值,这样用户头像才能上传成功,如下图:
这样当用户天按要求填写好其它信息后就能点击“提交”按钮进行注册了。
总结:
为了检验用户填写的数据的正确性,我们有两种办法:采用传统办法,自己编写客户端脚本进行验证;使用asp.net中的验证控件来进行验证。
CompareValidator控件、RangeValidator控件和RegularExpressionValidator控件对所关联的验证的空值是不进行验证的(即能通过验证),如果要求用户必须输入并且还要符合规则就要结合RequiredFieldValidator控件共同验证。
如果验证的规则比较复杂,则可以使用CustomValidator控件自己编写客户端验证代码来进行验证,如果要让CustomValidator控件对空值也进行客户端验证则要设置它的ValidateEmptyText属性为true。
个人经验:对于日期类的验证不建议使用正则进行验证,如果按照“yyyy-mm-dd”这样的形式对日期采用正则验证,那么“2008-02-31”这样值也是能通过验证的,虽然可以可以编写更严格的正则验证也是可以的(笔者曾经见过,正则表达式长度近千字节了,而且非常难以理解),其实用RangeValidator控件就能实现轻松验证,将它的Type属性设置为Date,并将的最大值和最小值分别设置为“9999-12-31”和“0001-01-01”就能避免出现2008-02-31”这样的值。也就是掌握了它们的规则灵活运用它们进行数据验证,提高数据的有效性。
--------------------------------------------------------------
后记:写这篇真有点吃力,查阅了大量有关正则方面的资料,调试N多次才将效果调试出来,历史4、5天的无数次失败的尝试得到了想要给大家展示的效果(知识点涉及CSS和javascript及正则等等),也算是不枉费大家的鼓励和希望了。我希望大家每次看的时候总能看到一些对实际开发有帮助但是以前没有用过或者没有想到的解决问题的思路和方法。
下一篇的内容可能会相对简单一点,讲述MultiView控件、Javascript方式的选项卡、WiZard控件和MasterPage母板页。可能内容不多,但是制作一些PP的网页时会派得上用场。
2008-10-28 02:35
周公(周金桥)
注意,因为个人空间大小和下载速度受限,所以以后不再提供从本人主机上的下载地址,可以到www.verycd.com下载《ASP.NET夜话》的测试版视频教程。地址是:http://www.verycd.com/topics/2730883/
Asp.net夜话系列文章:
- Asp.net夜话之一 :asp.net介绍
- Asp.net夜话之二 :asp.net内置对象
- asp.net夜话之三 :表单和控件
- Asp.net夜话之四 :Visual Studio 2005中容易被忽略的技巧
- asp.net夜话之五 :Page类和回调技术
- asp.net夜话之六 :asp.net基本控件
- asp.net夜话之七 :ADO.NET介绍
- asp.net夜话之八 :数据绑定控件
- asp.net夜话之 九:验证控件
- asp.net夜话之 十:复合控件和母板页
- asp.net夜话之十 一:web.config详解