【ASP.NET】基础补习之验证控件
在做Web应用程序的时候,因为用户有可能输入各式各样的信息,经常需要大量的数据验证,如果交给服务器去验证的话,无疑会增加服务器的压力,而且也容易造成程序的异常。甚至导致网站出现一些安全问题。因此我们在将这些信息保存到网站的数据库之前,要对这些用户所输入的信息进行数据的合法性校验,以便后面的程序可以安全顺利的执行。
ASP.NET提供了六种验证控件,可以实现以上功能。
- <!--[if !supportLists]-->RequiredFieldValidator(必须字段验证)
- <!--[if !supportLists]--><!--[endif]-->CompareValidator(比较验证)
- <!--[if !supportLists]-->RangeValidator(范围验证)
- <!--[if !supportLists]-->RegularExpressionValidator(正则表达式验证)
- <!--[if !supportLists]--><!--[endif]-->CustomValidator(自定义验证)
- <!--[if !supportLists]-->ValidationSummary(验证总结)
<!--[if !supportEmptyParas]--> <!--[endif]-->
验证控件基本成员:
- ControlToValidate – 要进行验证控件ID
- ErrorMessage – 验证失败时,出现的错误信息
- IsValid – 返回布尔值判断控件是否有效
- Validate – 验证控件的方法,同时改变IsValid属性
- Display– 错误信息的显示方式
- None (控件的错误信息在页面中占有肯定位置)
- Static (控件的错误信息出现时才占用页面控件.)
- Dynamic (错误出现时不显示.)
The RequiredFieldValidation Control
用于检查是否有输入值。用法如下:
Required field: <asp:textbox id="textbox1" runat="server"/> <asp:RequiredFieldValidator id="valRequired" runat="server" ControlToValidate="textbox1" ErrorMessage="* You must enter a value into textbox1" Display="dynamic">* </asp:RequiredFieldValidator>
以上例子,实现当用户在textbox1中输入数据后,提交才会有效,否则激活验证控件显示错误信息。
<!--[if !supportEmptyParas]--> <!--[endif]-->
The CompareValidator Control
按设定比较两个输入。CompareValidator可以用来验证注册时对密码的确认等。法如下:
Textbox 1: <asp:textbox id="textbox2" runat="server"/><br /> Textbox 2: <asp:textbox id="textbox3" runat="server"/><br /> <asp:CompareValidator id="valCompare" runat="server" ControlToValidate="textbox1" ControlToCompare="textbox2" Operator="Equals" ErrorMessage="* You must enter the same values into textbox 1 and textbox 2" Display="dynamic">* </asp:CompareValidator>
上面例子验证textbox1和textbox2必须一致,两个控件根据Operator属性进行比较。Operator属性可以设定为Equal, GreterThan, LessThanOrEqual等。CompareValidator的另一个用法是和一个固定值比较:
<!--[if !supportEmptyParas]--> Field: <asp:textbox id="textbox4" runat="server"/> <asp:CompareValidator id="CompareValidator1" runat="server" ControlToValidate="textbox1" ValueToCompare="50" Type="Integer" Operator="GreaterThan" ErrorMessage="* You must enter the a number greater than 50" Display="dynamic">* </asp:CompareValidator>
数据类型可以是Currency, Double, Date, Integer , String。String是默认属性。
The RangeValidator Control
验证输入是否在指定的范围。有三个必要的属性MaximumValue, MinimumValue, 和Type.
Enter a date from 1998: <asp:textbox id="textbox5" runat="server"/> <asp:RangeValidator id="valRange" runat="server" ControlToValidate="textbox1" MaximumValue="12/31/1998" MinimumValue="1/1/1998" Type="Date" ErrorMessage="* The date must be between 1/1/1998 and 12/13/1998" Display="static">*</asp:RangeValidator>
The RegularExpressionValidator Control
根据正则表达式验证。利用正则表达式可以灵活的对控件进行验证。正则表达式是一个优秀程序员必须掌握的技能之一。有关正则表的式的学习请参考 http://www.regexlab.com/zh/regref.htm
下面是一个简单的验证邮箱地址格式的例子:
E-mail: <asp:textbox id="textbox6" runat="server"/> <asp:RegularExpressionValidator id="valRegEx" runat="server" ControlToValidate="textbox1" ValidationExpression=".*@.*/..*" ErrorMessage="* Your entry is not a valid e-mail address." display="dynamic">* </asp:RegularExpressionValidator>
The CustomValidator Control
自定义验证控件,该控件用自定义的函数界定验证方式。ClientValidationFunction指定一个包含在html中的客户端验证函数。OnServerValidate是服务器端验证函数。
Field: <asp:textbox id="textbox7" runat="server"> <asp:CustomValidator id="valCustom" runat="server" ControlToValidate="textbox1" ClientValidationFunction="ClientValidate" OnServerValidate="ServerValidate" ErrorMessage="*This box is not valid" dispaly="dynamic">* </asp:CustomValidator> <script language="Javascript"> <!-- /* ... Code goes here ... */ --> </script>
服务器验证函数
代码语言:javascript复制
Sub ServerValidate (objSource As Object, objArgs As ServerValidateEventsArgs)
代码语言:javascript复制
' Code goes here
代码语言:javascript复制
End Sub
Validation Summary
总结验证结果。显示 Web 页上所有验证错误的列表。她的用法如下:
<asp:ValidationSummary id="valSummary" runat="server" HeaderText="Errors:" ShowSummary="true" DisplayMode="List" />
validation summary控件收集本页的所有验证错误信息,并可以将它们组织以后再显示出来。
(ShowMessageBox="True"时)
相关源码
<!--[if !supportEmptyParas]--> <!--[endif]-->
转载声明:本文转自http://publish.itpub.net/KnowledgeBase/Articles/8/0/0/80096171a275b7fc0e4941e461c5ee13.htm
==========================================================================
ASP.NET夜话
本篇要讲述的知识点如下: 数据验证介绍 纯客户端脚本验证 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" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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#" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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#" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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的整数时就能提交表单到服务器进行处理。 提示:其实所有的错误信息都是通过<span></span>方式输出的,当验证控件的Display属性为Static时输出的span格式是“<span style="color:Red; visibility:hidden;"></span>”这样的形式,当Display属性为Dynamic时输出的span格式是“<span style="color:Red; display:none;"></span>”这样的形式。
RangeValidator控件 RangeValidator控件也称之为范围验证控件,也就是只有当用户填写的非空数据不在指定的范围之间时就不能通过验证。除了具有BaseValidator所有的属性之外,它还具有如下常见属性:
属性名 | 说明 |
---|---|
MaximumValue | 允许的最大值 |
MinimumValue | 允许的最小值 |
Operator | 要执行的比较操作 |
Type | 对控件的值按照哪种方式进行比较,默认String |
下面是一个RangeValidator控件的例子。比如在实际中开发一个婚恋网站,里面有一栏是填写用户生日的,有一栏是用户填写生日信息的,因为婚恋网站是针对成年人的,所以我们可以根据用户填写的生日来确保用户填写表单时年龄在18岁至100岁之间(不要告诉我超过了100岁的人还搞婚恋,I服了U),如果未超过18岁则不能注册,这个时间是根据用户填写表单的时间进行判断的,所以我们没有直接给RangeValidator控件赋最大值和最小值,而是在页面运行获取当前服务器时间,用户所能填写的生日必须当前日期之前100年至18年之间,这样就保证了用户在注册时年龄在18岁至100之间。下面是代码:
- <%@ Page Language="C#" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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;
- //按照 数值=Unicode值=字符 的方式写入到Unicode.txt文件中
- //19968=/u4e00=一 即第一个汉字
- //40869=/u9fa5=龥 即最后一个汉字
- 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" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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属性表示被验证的控件的值。下面就是一个客户端验证函数的例子:
- <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))//用javascript进行客户端正则验证
- {
- args.IsValid=false;//表示未通过验证,出现错误提示
- }
- else if(args.Value%2==0)
- {
- args.IsValid=true;//表示通过验证,不出现错误提示
- }
- else
- {
- args.IsValid=false;//表示未通过验证,出现错误提示
- }
- }
- </script>
除了客户端验证之外,在CustomValidator控件中还能自己写服务器端写验证方法,它有一个OnServerValidate事件,同它的客户端处理函数一样,处理这个事件的委托也需要两个参数,第一个是表示被验证的控件,第二个表示事件数据。第二个参数有两个属性:IsValid用于表示被验证控件是否通过验证,Value属性表示被验证的控件的值。它服务器端验证方法设置界面如下:
下面我们用一个例子来说明CustomValidator控件的用法,在这里例子里用户被要求输入两个数,一个必须是2的倍数,一个必须是3的倍数。用CustomValidator控件就能很轻松完成这个功能。 下面是前台代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CustomValidatorDemo.aspx.cs" Inherits="CustomValidatorDemo" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <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>
.NET正则基础——.NET正则类及方法应用
1 概述 初学正则时,对于Regex类不熟悉,遇到问题不知道该用哪种方法解决,本文结合一些正则应用的典型应用场景,介绍一下Regex类的基本应用。这里重点进行.NET类的介绍,对于正则的运用,不做深入探讨。
正则的应用最终都是进行模式的匹配,而根据目的的不同,基本上可以分为以下几种应用:验证、提取、替换、分割。结合.NET提供的控件、类以及类的方法,可以很方便的实现这些应用。
以下将结合一些典型的应用场景,对.NET中常见的类、方法及属性进行介绍。本文旨在.NET类基础用法的引导,对于其中涉及到的正则表达式不做深入探讨。本文适合于在.NET平台下使用正则的初学者。
2 基础应用 2.1 验证 验证的目的是为了判断输入的源字符串是否符合某一规律或规则,根据需求的不同,可能是校验整个源字符串,也可能只是校验其中一个子串。
验证在.NET中一般有两种应用,一种是在验证控件RegularExpressionValidator中,另一种是在程序中。
2.1.1 验证控件RegularExpressionValidator RegularExpressionValidator是.NET自带的一种客户端验证控件,通过简单的设置,即可完成对某控件输入值的校验。
基本应用语法如下:
<asp:RegularExpressionValidator
ID="RegularExpressionValidator1"
runat="server"
ControlToValidate="TextBox1"
ErrorMessage="RegularExpressionValidator"
ValidationExpression="^([1-9][0-9]*|0)(/.[0-9][2])?$">
</asp:RegularExpressionValidator>
对于RegularExpressionValidator控件不做过多介绍,只是说明一下使用时需要注意的几点:
1、 RegularExpressionValidator进行的是客户端验证;
2、 RegularExpressionValidator中正则使用的是JavaScript语法规则;
3、 RegularExpressionValidator控件不能验证输入是否为空。
由于RegularExpressionValidator做的是客户端验证,很容易被跳过,所以在使用RegularExpressionValidator验证的同时,还要做服务器端验证。
RegularExpressionValidator最终是要生成客户端的JavaScript代码进行验证的,所以RegularExpressionValidator使用的正则要求符合JavaScript语法规则,与.NET的几点区别:
1、 不支持逆序环视,也就是(?<=Expression)和(?<!Expression)这样的语法;
2、 元字符仅支持ASCII码,即/w等价于[a-zA-Z0-9_],/d等价于[0-9]
RegularExpressionValidator控件一般是用来验证某一控件输入的字符串整体是否符合某一规则的,所以通常情况下“^”和“$”是必不可少的;在使用“|”表示“或”的关系时,一定要用“()”来限定“|”作用范围,比如0-100可以写作“^([1-9]?[0-9]|100)$”。
RegularExpressionValidator是不能验证输入是否为空的,验证是否为空要用RequiredFieldValidator控件。
RegularExpressionValidator验证控件是.NET为方便客户端验证封装的一组验证控件之一,但由于RegularExpressionValidator受限于支持的正则语法规则,只能做有限的格式校验,一些复杂的校验可以通过自己写JavaScript代码来实现,也是很简单的。
2.1.2 程序验证——IsMatch() 程序中的校验基本上就是使用IsMatch方法,验证的对象可能是源字符串的整体,也可能只是其中一个子串。
验证源字符串的整体是否符合某一规则,与使用RegularExpressionValidator时的需求基本上一致,不过由于是在.NET程序中,所以使用的是.NET的语法,比JavaScript中要强大得多。比如验证一个文本框输入的字符串是否符合某一规则,就是一个典型的验证整体的需求。
举例1:验证textBox1输入内容,要求整数部分为0或正整数,小数可有可无,有小数时必须为2位。
Regex reg = new Regex(@"^(?:[1-9][0-9]*|0)(?:/.[0-9]{2})?$");
if (reg.IsMatch(textBox1.Text))
{
richTextBox2.Text = "输入格式正确!";
}
else
{
richTextBox2.Text = "输入格式错误!";
}
由于是对源字符串的整体进行验证,所以“^”和“$”是必不可少的。否则验证的结果可能是错误的,比如正则表达式“(?:[1-9][0-9]*|0)(?:/.[0-9]{2})?”,在输入“0.123”时是可以匹配成功的,匹配结果为“0.12”,此时正则只起到了匹配的作用,没有起到验证的作用。
验证源字符串的局部是否符合某一规则,就是对于源字符串中子串的校验,通常是用来判断源字符串中是否包含,或是不包含符合某一规律的子串,作用类似于string类中的IndexOf。
举例2(参考问两个正则表达式):
数据:
1985aaa1985bb
bcae1958fiefadf1955fef
atijc1944cvkd
df2564isdjfef2564d
abc1234def5678ghi5678jkl
需求1:验证字符串中任意位置出现的连续四个数字在整个字符串中是否有重复,有重复为True,无重复为False。
以上数据需求1的验证结果为True的应为:
1985aaa1985bb
df2564isdjfef2564d
abc1234def5678ghi5678jkl
因为需求中指明是任意位置的连续4个数字是否有重复,所以在找到重复前,要遍历源字符串中每一个位置时行验证,这样就不能限定开始标识符“^”;而在匹配过程中,除非一直到结尾仍找不到重复,否则只要匹配到有重复的位置就可以了,这样也不需要结束标识符“$”,所以这是典型的对字符串的子串行验证的需求。
代码实现:
string[] test = new string[] { "1985aaa1985bb", "bcae1958fiefadf1955fef", "atijc1944cvkd", "df2564isdjfef2564d", "abc1234def5678ghi5678jkl" };
Regex reg = new Regex(@"(/d{4})(?:(?!/1).)*/1");
foreach (string s in test)
{
richTextBox2.Text = "源字符串: " s.PadRight(25, ' ') "验证结果: " reg.IsMatch(s) "/n";
}
/*--------输出--------
源字符串: 1985aaa1985bb 验证结果: True
源字符串: bcae1958fiefadf1955fef 验证结果: False
源字符串: atijc1944cvkd 验证结果: False
源字符串: df2564isdjfef2564d 验证结果: True
源字符串: abc1234def5678ghi5678jkl 验证结果: True
*/
由于涉及到了重复问题,所以这里用到了反向引用,对于反向引用的细节,可以参考正则基础之——反向引用。
需求2:验证字符串中第一个出现的连续4个数字是否有重复,有重复为True,无重复为False。
以上数据需求2的验证结果为True的应为:
1985aaa1985bb
df2564isdjfef2564d
因为需求中指明是第一个是否有重复,所以需要有开始标识符“^”,来保证是第一个出现的连续4个数字;而在匹配过程中,除非一直到结尾仍找不到重复,否则只要匹配到有重复的位置就可以了,这样也不需要结束标识符“$”,所以这仍是对字符串的子串行验证的需求,只不过相对于需求1来说,加了一个限定条件。
代码实现:
string[] test = new string[] { "1985aaa1985bb", "bcae1958fiefadf1955fef", "atijc1944cvkd", "df2564isdjfef2564d", "abc1234def5678ghi5678jkl" };
Regex reg = new Regex(@"^(?:(?!/d{4}).)*(/d{4})(?:(?!/1).)*/1");
foreach (string s in test)
{
richTextBox2.Text = "源字符串: " s.PadRight(25, ' ') "验证结果: " reg.IsMatch(s) "/n";
}
/*--------输出--------
源字符串: 1985aaa1985bb 验证结果: True
源字符串: bcae1958fiefadf1955fef 验证结果: False
源字符串: atijc1944cvkd 验证结果: False
源字符串: df2564isdjfef2564d 验证结果: True
源字符串: abc1234def5678ghi5678jkl 验证结果: False
*/
2.2 提取——Match()、Matches() 提取主要是从源字符串中,取得一个或多个符合某一规律或规则的子串。一般来说,在字符串处理中,提取应用比较广泛。提取时用得比较多的是Match()和Matches()方法,以及结果处理时Match类和MatchCollection类的一些方法,有时也会用到Capture类的一些方法。
2.2.1 提取单次匹配内容——Match() 当需要提取的内容只有一个,或是只需要获取第一次成功匹配的内容时,可以使用Match()方法。当使用Match()方法时,只要在某一位置匹配成功,就不再继续尝试匹配,并返回一个Match类型的对象。
举例:提取姓名
源字符串:姓名:张三,性别:男,年龄:25
代码实现:
string test = "姓名:张三,性别:男,年龄:25";
Regex reg = new Regex(@"(?<=姓名:)[^,] ");
Match m = reg.Match(test);
if (m.Success) //验证是否匹配成功
{
richTextBox2.Text = m.Value;
}
/*--------输出--------
张三
*/
虽然Match()只是取一次匹配,但是可以通过捕获组来获取多个指定子串,比如获取第一个<a…>标签的链接和文本。
string test = "abc<a href=/"www.test1.com/">测试一</a>def<a href=/"www.test2.com/">测试二</a>ghi";
Regex reg = new Regex(@"(?is)<a(?:(?!href=).)href=(['""]?)(?<url>[^""/s>]*)/1[^>]*>(?<text>(?:(?!</?a/b).)*)</a>");
Match m = reg.Match(test);
if(m.Success)
{
richTextBox2.Text = m.Groups["url"].Value "/n"; //链接
richTextBox2.Text = m.Groups["text"].Value "/n"; //文本
}
/*--------输出--------
www.test1.com
测试一
*/
对于捕获组捕获结果的引用,还有一种方式
string test = "abc<a href=/"www.test1.com/">测试一</a>def<a href=/"www.test2.com/">测试二</a>ghi";
Regex reg = new Regex(@"(?is)<a(?:(?!href=).)href=(['""]?)(?<url>[^""/s>]*)/1[^>]*>(?<text>(?:(?!</?a/b).)*)</a>"); Match m = reg.Match(test);
if(m.Success)
{
richTextBox2.Text = m.Result("${url}") "/n"; //链接
richTextBox2.Text = m.Result("${text}") "/n"; //文本
}
/*--------输出--------
www.test1.com
测试一
*/
这两种方法获取的结果都是一样的,使用哪一种,通常根据个人习惯而定。
2.2.2 提取多次匹配内容——Matches() 当需要提取的内容有多个,并且需要提取所有符合规律的子串时,可以使用Matches()方法。当使用Matches()方法时,需要遍历源字符串的每一个位置进行尝试匹配,匹配结束返回一个MatchCollection类型的对象。
对于1.2.1节提到的提取链接和文本的例子,如果提取的是全部链接和文本,而不仅仅是第一个时,可以使用Matches()方法。
string test = "abc<a href=/"www.test1.com/">测试一</a>def<a href=/"www.test2.com/">测试二</a>ghi";
Regex reg = new Regex(@"(?is)<a(?:(?!href=).)href=(['""]?)(?<url>[^""/s>]*)/1[^>]*>(?<text>(?:(?!</?a/b).)*)</a>");
MatchCollection mc = reg.Matches(test);
foreach(Match m in mc)
{
richTextBox2.Text = m.Groups["url"].Value "/n"; //链接
richTextBox2.Text = m.Groups["text"].Value "/n"; //文本
}
/*--------输出--------
www.test1.com
测试一
www.test2.com
测试二
*/
对于Matches(),某些场景下,也可以通过Count属性,用做统计符合某一规律的子串出现的次数,例如统计字符串中独立的“3”出现的次数。
string test = "137,1,33,4,3,6,21,3,35,93,2,98";
Regex reg = new Regex(@"/b3/b");
int count = reg.Matches(test).Count; //2
这时候关心的只是匹配成功的次数,对于匹配的内容是不关心的,所以实现这种需求时,正则应尽量简洁,能达到目的即可,这样可以加快匹配效率,减少资源占用。比如上面的提取链接的源字符串中,统计<a…>标签出现的次数,一般来说,如下代码即可达到目的了。
string test = "abc<a href=/"www.test1.com/">测试一</a>def<a href=/"www.test2.com/">测试二</a>ghi";
Regex reg = new Regex(@"(?i)<a/b");
int count = reg.Matches(test).Count; //2
2.2.3 捕获组匹配过程集合——Capture 在某些情况下,一个正则表达式整体匹配一次时,其中的捕获组可能会匹配多次。
举例:
源字符串:<region name=oldslist col=1 row=2 order=asc>abcsadf </region> jfdsajf <region name=newslist class=list col=4 row=10 order=desc>abcsadf </region>
需求:提取出每个region的属性和属性值,按region分组。
对于这个需求,可以先提取出所有region,再对每个region标签提取它的属性和属性值,但这样做比较麻烦,可以考虑在一个正则表达式中提取。由于属性的个数是不固定的,所以不能用固定个数的量词来匹配属性对,正则可以写为
(?is)<region/s (?:(?<key>[^/s=] )=(?<value>[^/s>] )/s*) >
此时如果还用Groups来取匹配结果时,由于Groups只保留最后一次匹配结果,所以只能取到最后一次匹配成功的子串。这时就要用到Captures属性。
string test = "<region name=oldslist col=1 row=2 order=asc>abcsadf </region> jfdsajf <region name=newslist class=list col=4 row=10 order=desc>abcsadf </region>";
MatchCollection mc = Regex.Matches(test, @"(?is)<region/s (?:(?<key>[^/s=] )=(?<value>[^/s>] )/s*) >");
for (int i = 0; i < mc.Count; i )
{
richTextBox2.Text = "第" (i 1) "个region的属性:/n";
for (int j = 0; j < mc[i].Groups["key"].Captures.Count; j )
{
richTextBox2.Text = "属性: " mc[i].Groups["key"].Captures[j].Value.PadRight(10, ' ') " 值: " mc[i].Groups["value"].Captures[j].Value "/n";
}
richTextBox2.Text = "/n";
}
/*--------输出--------
第1个region的属性:
属性: name 值: oldslist
属性: col 值: 1
属性: row 值: 2
属性: order 值: asc
第2个region的属性:
属性: name 值: newslist
属性: class 值: list
属性: col 值: 4
属性: row 值: 10
属性: order 值: desc
*/
Group实际上是Capture的一个集合,在捕获组只匹配一个子串时,这个集合只有一个元素,而在捕获组先后匹配多个子串时,Groups[i].Value只保留最后一个匹配结果,而Capture集合却可以记录匹配过程中匹配到的所有子串。
Capture的应用场景并不多,对于上面的例子,如果不使用 Capture,可以通过分次匹配的方式实现,但是在一些复杂的表达式中,很难进行分次匹配,这时Capture就比较有用了。
2.3 替换 替换主要是从源字符串中,将符合某一规律或规则的子串替换为其它内容。一般来说,在字符串处理中,替换应用也比较广泛。替换主要是用Replace()方法,在一些替换规则复杂的应用场景中,也可能会用到委托方法。
2.3.1 一般替换 替换的目的很明确,只要找出待替换子串的规律,替换为目标子串就可以了。
举例1:
源字符串:<img src="/imgs/logo.jpg"> abc <img src="http://www.test.com/imgs/top.gif">
需求:将相对地址替换为绝对地址,已经是绝对地址的不替换。
string test = "<img src=/"/imgs/logo.jpg/"> abc <img src=/"http://www.test.com/imgs/top.gif/">";
Regex reg = new Regex(@"(?i)(?<=src=(['""]?))(?!http://)(?=[^'""/s>] /1)");
string result = reg.Replace(test, "http://www.test.com");
/*--------输出--------
<img src="http://www.test.com/imgs/logo.jpg"> abc <img src="http://www.test.com/imgs/top.gif">
*/
这里需要说明的是,在.NET中只提供了一个Replace()方法,没有提供类似于Java中的replaceAll()和replaceFirst()两种方法,所以如果在.NET中只替换第一次出现的符合规律的子串时,需要在正则表达式中处理。
举例2:
源字符串:abc123def123ghi
需求:将第一次出现的“123”替换为空,其余位置不替换。
string test = "abc123def123ghi";
Regex reg = new Regex(@"(?s)^((?:(?!123).)*)123");
string result = reg.Replace(test, "$1");
/*--------输出--------
abcdef123ghi
*/
这时用“^”限定只替换第一次出现的子串,由于绝大多数正则引擎都对“^”进行了优化,所以正则表达式在位置0处匹配成功或失败后,将不再对其它位置进行尝试匹配。
2.3.2 替换中的委托方法应用 对于一些比较复杂的替换规则,可能会用到委托方法,由于这种应用属于比较典型的一种应用,所以将在后面的文章中单独进行介绍。
2.4 分割 分割就是用符合某一规律的子串,将源字符串分割成一个数组,主要用到的是Split()方法。由于Regex的Split()方法中,并没有提供类似于string的Split()方法的StringSplitOptions.RemoveEmptyEntries参数,而如果符合规律的子串出现在开头或结尾时,会出现不需要的空串,这时需要在正则表达式中进行一下处理。
举例1:
源字符串:汉字123文字english
需求:按英文单词和非英文单词进行分割(英文单词包括由a-z,A-Z,0-9,_组成的子串)。
string str = "汉字123文字english";
string[] result = Regex.Split(str, @"(?<!^)/b(?!$)", RegexOptions.ECMAScript);
foreach (string s in result)
{
richTextBox2.Text = s "/n";
}
/*--------输出--------
汉字
123
文字
English
*/
这里分别用“(?<!^)”和“(?!$)”来限定不以开头或结尾的子串进行分割,结果中也就不会出现不必要的空串了。
还有一些应用,其实可以算作是正则就用技巧范畴的了。
举例2:
源字符串:Left(姓名,1),Left(姓名,1) , Left (姓名,1)
需求:以不在“()”内的“,”进行分割。
string test = "Left(姓名,1),Left(姓名,1) , Left (姓名,1)";
Regex reg = new Regex(@"(?<!/([^)]*),(?![^(]*/))");
string[] sArray = reg.Split(test);
foreach (string s in sArray)
{
richTextBox2.Text = s "/n";
}
/*--------输出--------
Left(姓名,1)
Left(姓名,1)
Left (姓名,1)
*/
使用正则的Split()方法时,有一点需求注意,那就是如果正则中出现了捕获组,那么捕获组匹配到的内容也会保存到分割结果中。
以下举例不做详细说明,看下结果基本上就明白了。
string test = "aa11<bbb>cc22<ddd>ee";
string[] temp = Regex.Split(test, @"[0-9] (<[^>]*>)");
foreach (string s in temp)
{
richTextBox2.Text = s "/n";
}
/*--------输出--------
aa
<bbb>
cc
<ddd>
ee
*/
如果不想把捕获组匹配到的内容也存入结果,可以使用非捕获组。
string test = "aa11<bbb>cc22<ddd>ee";
string[] temp = Regex.Split(test, @"[0-9] (?:<[^>]*>)");
foreach (string s in temp)
{
richTextBox2.Text = s "/n";
}
/*--------输出--------
aa
cc
ee
*/
3 扩展应用 这里介绍一些可能涉及到的一些.NET中的正则扩展应用。
3.1 动态生成正则时的转义——Escape() 有时需要根据一些变量动态生成正则表达式,这时如果变量中含有正则中的元字符,会被解析成元字符,就可能会导致正则编译不通过,从而导致程序异常,需要对变量进行转义处理。Regex. Escape()方法通过替换为转义码来转义最小的字符集(/、*、 、?、|、{、[、(、)、^、$、.、# 和空白)。
比如根据用户输入的id取相应的div标签,id中没有元字符时,可以取得正确结果。
string test = "<div id=/"test1/">abc</div><div id=/"test2/">def</div>";
string[] ids = new string[] { "test1", "test2" };
foreach (string id in ids)
{
Regex reg = new Regex(@"(?is)<div/s id=""" id @"""[^>]*>(?:(?!</?div/b).)*</div>");
MatchCollection mc = reg.Matches(test);
foreach (Match m in mc)
{
richTextBox2.Text = m.Value "/n";
}
}
/*--------输出--------
<div id="test1">abc</div>
<div id="test2">def</div>
*/
但是如果输入的id中一旦出现未经转义的元字符,如“abc(”,就会抛类似于下面的异常。
正在分析“(?is)<div/s id="abc("[^>]*>(?:(?!</?div/b).)*</div>”- ) 不足。
此时可以用Escape()方法对输入的变量进行转义处理。
string test = "<div id=/"test1/">abc</div><div id=/"test2/">def</div>";
string[] ids = new string[] { "test1", "test2", "abc(" };
foreach (string id in ids)
{
Regex reg = new Regex(@"(?is)<div/s id=""" Regex.Escape(id) @"""[^>]*>(?:(?!</?div/b).)*</div>");
MatchCollection mc = reg.Matches(test);
foreach (Match m in mc)
{
richTextBox2.Text = m.Value "/n";
}
}
/*--------输出--------
<div id="test1">abc</div>
<div id="test2">def</div>
*/
使用Escape()方法转义后,就可以得到正确的结果,而不会抛异常了。
3.2 静态方法 .NET中一些Regex类的常见方法都提供了相应的静态方法,可以不显式的声明Regex对象,而直接调用相应的方法,书写起来更方便,代码更简洁、易读。
比如替换IP地址最后一节为“*”,只需一行代码。
string result = Regex.Replace("10.27.123.12", @"/d $", "*"); //10.27.123.*
静态方法每次调用都会创建一个临时的Regex对象,使用之后释放,所以每次调用静态方法时,都会重新编译,而这将会降低执行效率。因此在循环或是频繁调用的方法中,不适合使用静态方法,而需要进行显式声明Regex对象。
但是对于一些只调用一次,或是对执行效率没有要求的场景下,静态方法则是很不错的选择。
转载声明:本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lxcnn/archive/2009/10/12/4656599.aspx
对以上各篇原创作者分享技术经验深表感谢与敬意!也希望有更多的人学习和参入到技术交流中来,相互学习,共同进步…… 谢谢!
转载声明:
本文转自http://cache.baidu.com/c?m=9d78d513d98312f30dbad02d534d81355f09c0743ca690422a93cd1bd33311030731a2fa7c7f4c40809b273152e9141cfdf04765460637c391dff849cacf903c68c8793b2a5ac00305d26ab2d6167b9c75875a9efe58b1e6e732e4f28595c21c0997145127caa1d74753549b35ab5066fea69b4a1f4213b8f0306fe258742d992242b450f997612f45cb&p=c36fcd15d9c341e70be293311749&user=baidu
==========================================================================