第13课:正则表达式(2)
本课继续讨论正则表达式的相关操作,主要包括反向引用和环视,最后还会封装一些常用操作,如E-mail地址格式验证、删除文本中的所有空白字符,以及15位和18位身份证号码规则的验证等操作。
反向引用
反向引用构造可更加方便地匹配重复内容,首先来看数字反向引用构造的应用。如文本中需要匹配连续的相同字符,可以参考如下代码。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @"(\w)\1";
tWeb.WriteLine(Regex.IsMatch("apple",pattern)); // True
tWeb.WriteLine(Regex.IsMatch("orange",pattern)); // False
}
}
|
本例,子表达式(\w)表示一个字母、数字或下画线字符,\1则表示与第一个子表达式相同,这样就定义了连续两个相同的字符模式。第一个输出中,apple中包含连续的p,匹配结果为True;第二个输出中,orange没有连续的相同字母,匹配结果为False。
如果自动的数字编号不够清晰,也可以为子表达式指定明确的编号,将上例中的模式修改为如下代码可以得到相同的运行结果。
C# |
string pattern = @"(?<1>\w)\1";
|
代码中,在子表达式里使用?<n>格式定义数字编号。
除了使用数字命名子表达式,也可以使用文本形式的表达式名称,如将前面的示例修改为下面的模式也可以得到相同的结果。
C# |
string pattern = @"(?<char1>\w)\<char1>";
|
使用反向引用构造,在匹配相同的内容时,除了连续的内容,也可以在文本中匹配对称的内容,比如,对HTML代码的检索时匹配h1到h6的元素,下面的代码演示了相关应用。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @"<h([1-6])>.+?<\/h\1>";
string code = @"<h1>标题一</h1>
<p>段落一</p><h2>标题二</h2><p>段落二</p><h3>标题三</h3>";
foreach(Match m in Regex.Matches(code, pattern))
{
tWeb.WriteLine(Server.HtmlEncode(m.Value));
}
}
}
|
运行代码会匹配的h1、h2和h3元素,代码中还使用了Server.HtmlEncode()方法将匹配内容进行HTML转码,最终显示结果如图1。
图1
环视
环视的功能是匹配一个位置,然后获取此位置前面的内容(向前查看)或后面的内容(向后查看)。
Email地址的格式是“<用户名>@<域名>”,如果需要通过正则表达式读取用户名和域名部分,则可以通过环视来实现,如下面的代码,使用向前查看获取Email地址中的用户名部分。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @".+(?=@)";
string s = "xxx@yyy.zzz";
Match match = Regex.Match(s, pattern);
tWeb.WriteLine(match.Value);
}
}
|
模式中的(?=@)部分定义了环视规则,?=表示向前查看,而@则表示@字符所在位置,执行代码会显示@前的内容,即Email地址中的用户名部分xxx。
向后查看时使用?<=限定符,如下面的代码会显示Email地址中的域名部分。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @"(?<=@).+";
string s = "xxx@yyy.zzz";
Match match = Regex.Match(s, pattern);
tWeb.WriteLine(match.Value);
}
}
|
执行代码会显示yyy.zzz,即@符号后面的内容。
环视限定符还包括?!(否定式向前查看)和?<!(否定式向后查看)。在模式中,如果需要查询单独的go单词,可以使用@"\bgo\b"模式,如果需要查询以go开头的单词,但又不是单独的go单词时,可以使用如下代码。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @"\bgo(?!\b)";
tWeb.WriteLine(Regex.IsMatch("go",pattern)); // False
tWeb.WriteLine(Regex.IsMatch("goto", pattern)); // True
}
}
|
代码中定义的模式,左边是字边界也就是指定单词应以go开始,在子表达式(?!\b)中,表示go后不应是字边界,也就是说不能是独立的单词go。
?<!(否定式向后查看)表示不能以指定的内容开始,如下面的代码。
C# |
using System;
using System.Text.RegularExpressions;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string pattern = @"\b\w+(?<!ing)\b";
tWeb.WriteLine(Regex.IsMatch("going",pattern)); // False
tWeb.WriteLine(Regex.IsMatch("goto", pattern)); // True
}
}
|
代码中的模式会匹配不以ing结束的单词,going匹配结果为False,goto匹配结果为True。
综合应用
熟练掌握正则表达式需要大量的实践,在定义模式时也有很多技巧,一个功能也可以使用多种实现方法,比如,在帮助文档的示例中判断E-mail地址的模式定义如下:
C# |
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
|
其中,除了必须的@和圆点(.)符号,其它部分定义了不应包含空字符。这里,也可以要求只能包含哪些字符,如下面的模式。
C# |
string pattern = @"^[a-zA-Z0-9](\w+\.)*\w+@(\w+\.)+\w+$";
|
开发中,可以根据需要定义或扩展检查规则。本书代码中会使用tStr.IsEmail()方法判断文本是否为有效的E-mail地址。
此外,需要注意的是,只判断E-mail地址并不能邮箱是否真正有效;在真实的应用环境中,可以通过发送确认邮件的形式判断邮箱的有效性。
接下来将封装一些常用的功能,包括删除文本中的所有空白字符,以及身份证号码验证的相关操作。