正则表达式入门(2)

示例2

e-mail的匹配

就从博客园的联系方式页面来找就好了,地址是 http://www.cnblogs.com/ContactUs.aspx

 

准备工作:

获取页面内容,方法如下:

static string DownloadString(Uri url, Encoding encoding)
{
    WebClient client;
    using (client = new WebClient())
    {
return encoding.GetString(client.DownloadData(url));
    }
}

只适用于简单的情况,已经足够了,下面是示例

static void example2()
{
    Uri url;
    Encoding encoding;
    string content;
    Regex regex;
    MatchCollection matches;

    string expression;

    url = new Uri("http://www.cnblogs.com/ContactUs.aspx");
    encoding = Encoding.UTF8;//博客园是utf-8的,直接指定了

    content = DownloadString(url, encoding);

    expression = "[-_0-9A-Z]{1,20}(@|&\\#64;)[-0-9A-Z]+(\\.com|\\.net)";

    regex = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);

    matches = regex.Matches(content);

    foreach (Match match in matches)
    {
        Console.WriteLine(string.Concat("'", match.Value.Replace("@", "@"), "'"));
    }
}

e-mail 的格式为 {用户名}@{域名}

为了看起来比较简单,我们假设用户名只能由"-","_",0-9的数字和A-Z的字母 组成

所以用户名部分就是[-_0-9A-Z],但是有一点需要注意,第一个"-"和后面的"-"的含义是不一样的,第一个的意思是"-"这个字符本身,后面的代表的是范围,范围是通过"a-b"这样的方式来确定的,如果需要匹配"-"这个字符本身,尽量不要放在歧义的位置。

 

然后是第二部分 "(@|&\\#64;)" 是包含在括号之间的,原因在于这里由2部分组成,其中用|分开,表示多选一,"@" 或者 "@"(@的ascii就是64,可以用"@",  "#"字符在正则中需要转义,需要转义的字符可以在msdn中找到,地址是 http://msdn.microsoft.com/zh-cn/library/system.text.regularexpressions.regex.escape(v=vs.110).aspx,需要转义的字符只要在前面加上"\\"即可)如果外面没有括号来限制,那这个多选分支的范围就扩大了,把"|"两边作为一个多选分支,那就变成了  "{用户名}@" 或者 "@{域名}",不是我们想要的情况。

 

[-0-9A-Z]+(\\.com|\\.net)

最后是域名部分,目前只接受".net"或者".com"这2个顶级域名 类似 "cnblogs.com" 这样的形式

前面部分由至少一个的 数字,字母或者"-"组成,后面只允许".com"或者".net"还是用|来做到

 

最后 RegexOptions.IgnoreCase 表示忽略大小写,不然,这个表达式可能要写成

"[-_0-9A-Za-z]{1,20}(@|&\\#64;)[-0-9A-Za-z]+(\\.[cC][oO][mM]|\\.[nN][eE][tT])"
不够直观
 

 

好了,看一下结果

'contact@cnblogs.com'
'contact@cnblogs.com'

一共有2个匹配

 

不过,如果要把用户名和域名都取出来好像有点麻烦

稍微改进一下,代码如下:

static void example2()
{
    Uri url;
    Encoding encoding;
string content;
    Regex regex;
    MatchCollection matches;

string expression;

    url = new Uri("http://www.cnblogs.com/ContactUs.aspx");
    encoding = Encoding.UTF8;

    content = DownloadString(url, encoding);

    expression = "([-_0-9A-Z]{1,20})(@|&\\#64;)([-0-9A-Z]+(\\.com|\\.net))";

    regex = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);

    matches = regex.Matches(content);

foreach (Match match in matches)
    {
        Console.WriteLine(string.Format(
"e-mail: '{0}', userName: '{1}', domain: '{2}'",
            match.Groups[0].Value.Replace("@", "@"),
            match.Groups[1].Value,
            match.Groups[3].Value
        ));
    }
}

先看看改动

"[-_0-9A-Z]{1,20}" 变成了 "([-_0-9A-Z]{1,20})"

"[-0-9A-Z]+(\\.com|\\.net)" 变成了 "([-0-9A-Z]+(\\.com|\\.net))"

只是在外面加了对括号

默认情况下,会为每对括号创建一个捕获分组(capture group)

看一下完整的表达式 "([-_0-9A-Z]{1,20})(@|&\\#64;)([-0-9A-Z]+(\\.com|\\.net))"

第一个分组是:"([-_0-9A-Z]{1,20})"

第二个分组是:"(@|&\\#64;)"

第三个分组是:"([-0-9A-Z]+(\\.com|\\.net))"

第四个分组是:"(\\.com|\\.net)"

其中第四个是嵌套在第三个之中

这样,就可以通过Match.Groups[下标]来获取对应的分组了,其中Groups[0]就是完整的匹配

 

这样还是不够直观,再做一次更改

改动后代码如下:

static void example2()
{
    Uri url;
    Encoding encoding;
    string content;
    Regex regex;
    MatchCollection matches;

    string expression;

    url = new Uri("http://www.cnblogs.com/ContactUs.aspx");
    encoding = Encoding.UTF8;

    content = DownloadString(url, encoding);

    expression = "(?<userName>[-_0-9A-Z]{1,20})(@|&\\#64;)(?<domain>[-0-9A-Z]+(\\.com|\\.net))";

    regex = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture);

    matches = regex.Matches(content);

    foreach (Match match in matches)
    {
        Console.WriteLine(string.Format(
            "e-mail: '{0}', userName: '{1}', domain: '{2}'",
            match.Groups[0].Value.Replace("&#64;", "@"),
            match.Groups["userName"].Value,
            match.Groups["domain"].Value
        ));
    }
}

"([-_0-9A-Z]{1,20})"变成了"(?<userName>[-_0-9A-Z]{1,20})"

"([-0-9A-Z]+(\\.com|\\.net))"变成了"(?<domain>[-0-9A-Z]+(\\.com|\\.net))"

都是在括号开始的地方加上了?<名称>

这是命名分组捕获可以用以下方式调用

match.Groups["userName"]

match.Groups["domain"]

 

posted on 2014-01-18 22:10  viago  阅读(286)  评论(0编辑  收藏  举报