正则学习
正则表达式地狱-天堂之说,源自老程序员的话.老程序员告诉我们,没有正则表达式就像地狱一般,有了正则表达式我们就像进了天堂一样.好,我们下面看这么几个需求: 需求1:“192.168.10.5[port=8080]”,这个字符串表示IP地址为192.168.10.5的服务器的8080端口是打开的,请用程序解析此字符串,然后打印出“IP地址为***的服务器的***端口是打开的”。 需求2:“192.168.10.5[port=21,type=ftp]”,这个字符串表示IP地址为192.168.10.5的服务器的21端口提供的是ftp服务,其中如果“,type=ftp”部分被省略,则默认为http服务。请用程序解析此字符串,然后打印出“IP地址为***的服务器的***端口提供的服务为***” 需求3:判断一个字符串是否是Email?必须含有@和.、不能以@或者.开始或者结束、@要在最后一个.之前(这个给点时间用我们之前的字符串的相关内容能做出来,但是太多了.) 需求4:从一个文本中提取出所有的Email:我有全部333M的照片,要的给我发email:me@wo.com。我也要you@you.com,123456@163.com,楼主好人:888888@qq.cn。 (论坛中如百度贴吧中,可以自己做个种子搜索器.请看下图)
一、查找网页中的e-mail 类似于这种情况,我们用普通的方法实现非常的困难。有个非常好的处理方法,就是正则表达式。正则表达式就是对字符串的操作。 正则是语言无关的,很多的语言当中都能用到正则表达式。 那么,到底正则表达式是个啥呢?实际上就是一些通配符。 正则给我们一些元字符,这些元字符可以理解成一些已经定义好的通配符,使用它们在字符串中找到我们想要的匹配。 那么正在等用处很多,像采集器、敏感词过滤、URLRewite、Validator中都会用到。 下面我们介绍一些元字符: 第一种是: .:匹配除n之外的任何单个字符。 第二种是: [ ] :匹配括号中的任何一个字符。 如果要想匹配二十六个英文字母中的任意一个怎么写呢? a[a-z]b 如果也想匹配大写的A—Z的话,需要这么写 a[a-zA-Z]b 第三种是: | :将两个匹配条件进行逻辑“或”运算。 如a[a|b]b z|food 要么是z,要么是food (z|f)ood 加小括号改变优先级 第四种是: ( ) :将 () 之间括起来的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域,这个元字符在字符串提取的时候非常有用。把一些字符表示为一个整体。改变优先级、定义提取组两个作用。 元字符2(限定符): 第一种是: *:匹配0至多个在它之前的子表达式,和通配符*没关系。 如 zoo*,*表示可以出现0次,也可以出现多次。(可有可无,可多可少) 第二种是: + :匹配前面的子表达式一次或多次 如zoo+,+表示可以出现一次,或者是多次。(至少得出现一次。) 注意:* +只表示o的出现次数,要是想表示前面的整个表达式,得用小括号括起来。 第三种是: ? :匹配前面的子表达式零次或一次。 如zoo? ,要么0次,要么1次。 第四种是: {n} :匹配确定的 n 次。 第五种是: {n,m} :最少匹配 n 次且最多匹配 m 次。 元字符3 第一种是: ^(shift+6) :匹配一行的开始。如^xxx. 表示字符串必须以三个先开头,后面跟任意的单个字符。 它还有一个意思就是取反的意思,如 a[^a-zA-Z0-9]b 表示中间去大小写字符和数字都不行。 第二种是: $ :匹配行结束符。 如xxx.$ 表示结尾必须以xxx加任意字符结束。 接下来我们再看一些个元字符(一些简写的方式): 第一种是: d:代表一个数字,等同于[0-9] 如a[0-9]b adb 第二种是: D:代表非数字,等同于[^0-9] 第三种是: s:代表换行符、Tab制表符等空白字符,(空格、回车、制表符) 第四种是: S:代表非空白字符(a0%$@@) 第五种是: w:匹配字母或数字或下划线或汉字,即能组成单词的字符,除%&#@!$等字符。[a-zA-Z0-9_汉字] 第六种是: W:非w ,等同于[^w] % 需要注意的地方:当放在C#中时,需要在它们之前加个 正则表达式字符类下载地址: 下面我们主要讲解怎么去用这些正则表达式: 二、使用正则需要用到的类及导入命名空间 三、正则的几种用法 四、这是个什么类? 五、验证邮箱是否匹配代码 六、不能这么写 字符串不能这么写,字符串不能按数学上的区间来表示,写正则永远都是先找规律。 七、找规律 八、验证用户输入的数字字符串代码 字符串匹配例子: Regex.IsMatch("bbbbg","^b.*g$");匹配,以b开头以g结尾,中间出现任意字符 Regex.IsMatch("bg","^b.*g$");匹配,中间有也行,没有也行。 Regex.IsMatch("gege","^b.*g$");不匹配,开头要求是b,但是字符串不是。 下面写个验证身份证号码的正则,要求:要么是15位,要么是18位的数字。 扩展在15位的时候,前14位是数字,最后一位是大小写x。 九、验证身份证号码代码 十、小作业 这个题我们可以在VS里面调试一下,试试。 十一、小作业答案 十二、衍生题目 十三、电话号码验证代码 验证如果非常的灵活的话,可以把验证单独提取到配置文件里面。将来正则表达式直接读取配置文件就可以了。配置文件想怎么改怎么改。 十四、验证email的正则 十五、自己写的邮箱验证 关于正则比较讨厌的问题是,它不好测试。出错之后必须自己去分析。 下面我们做下如下几个练习: 1、匹配IP地址,4段用.分割的最多三位数字。 192.168.54.77、333.333.333.333假设都是正确的。 1.2.222.3 192.168.0.156 十六、验证ip的正则代码 2、判断是否是合法的日期格式“2008-08-08”。四位数字-两位数字-两位数字。 十七、判断是否是合法的日期格式代码 3、判断是否是合法的url地址,http://www.test.com/a.htm?id=3&name=aaa、ftp://127.0.0.1/1.txt。字符串序列://字符串序列。 十八、判断url地址的正则 答案完整版: 1、匹配IP地址,4段用.分割的最多三位数字。 192.168.54.77、333.333.333.333假设都是正确的。 "@“^d{1,3}.d{1,3}$”。.是正则表达式中的特殊含义,因此需要转义。进一步严谨:^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$ "2、判断是否是合法的日期格式“2008-08-08”。四位数字-两位数字-两位数字。@“^d{4}-d{2}-d{2}$”,进一步严谨:^d{4}-((0[1-9])|(1[0-2]))-((0[1-9])|(1[0-9])|(2[0-9])|(3[0-1]))$ 3、判断是否是合法的url地址,http://www.test.com/a.htm、ftp://127.0.0.1/1.txt。字符串序列://字符串序列。@"^w+://.+$"。//简化的识别,项目中google搜“w3c URL 正则表达式”。.+而不是w,否则"?id=1"中的?就不能匹配了。 http://www.test.com/a.aspx?id=1 取巧的办法:从ASP.Net的RegularExpressionValidator中抄常用的正则表达式,工作中一般是从网上找现成的。或者去http://www.regexlib.com/ 搜索。 上面推荐了一个正则的网址,非常的好用,大概演示一下子。 十九、想搜什么对应的输入就行了 下面我们看下正则表达式提取 二十、match方法 二十一、能不能for能不能foreach 二十二、为什么var不智能推断了呢? 二十三、原因 二十四、提取所有用matches 下面我们提取网页中所有的email 分享我多年收集的关于正则表达式的素材 正则表达式素材1下载地址: 正则表达式素材2: 正则表达式素材3: 正则表达式素材4: 正则表达式素材5: 二十五、把素材考进来 二十六、检查下是否是乱码 二十七、提取网页中的email的代码 请统计出126邮箱的使用人数,gmail邮箱的使用人数,并且把每个人的用户名单独的输出。 可以用我们很早以前讲过的split截取来做这个题.我们用正则表达式也能解决这个问题. 在介绍这个之前,我们先给大家介绍个稍微简单点的.
二十八、提取组 二十九、看左括号 三十、用正则提取组解决刚才的问题 字符串提取练习1(提取组练习) 从文件路径中提取出文件名(包含后缀) @"^.+(.+)$"。比如从c:windowstestb.txt中提取出testb.txt这个文件名出来。项目中用Path.GetFileName更好。贪婪模式。(想一下,这个时候怎么提取文件名?) 三十一、提取文件名练习 从“June 26,1951 ”中提取出月份June、26、1951来。@"([a-zA-Z]+)s+d{1,2},s*d{4}"进行匹配。月份和日之间是必须要有空格分割的,所以使用空白符号“s”匹配所有的空白字符,此处的空格是必须有的,所以使用“+”标识为匹配1至多个空格。之后的“,”与年份之间的空格是可有可无的,所以使用“*”表示为匹配0至多个 三十二、提取月日年 从Email中提取出用户名和域名,比如从test@163.com中提取出test和163.com。 这个我们就不用说了。 “192.168.10.5[port=21,type=ftp”部分被省略,则默认为http服务。请用程序解析此字符串,然后打印出“IP地址为***的服务器的***端口提供的服务为***” 三十三、提取ip端口号服务类型的正则 接下来我们看下贪婪模式与非贪婪模式 三十四、贪婪模式 三十五、终止贪婪模式 下面我们看一个案例: 三十六、案例1 三十七、案例2 三十八、案例3 三十九、案例3终止贪婪模式 案例:从一个页面提取所有Email地址,用WebClient,自己动手写Email群发器。
四十、提取网页中的email 练习:从网站抓取所有的图片地址,下载到硬盘:MatchCollection matches = Regex.Matches(content,"border=0s*src="(.*?)">");//<img.*?src=(.+)?.*?/> 我们这里用个本地图片。 四十一、本地下载 我们把它模拟成互联网上访问, 四十二、把网站部署在“网络”上 上面这个小工具已经放到文章上面的资源里面供大家下载。 四十三、下载网络图片 下载网络图片代码插入位置:
View Code
1 #region 下载网页图片 2 WebClient wc = new WebClient(); 3 //先把地址下载下来 4 string html = wc.DownloadString("http://localhost:8080/美女们.htm"); 5 //根据网页源代码写正则 6 MatchCollection matches = Regex.Matches(html,"<img alt="" src="(.+)" />"); 7 //循环一下,看看有没有匹配。 8 int index = 0; 9 foreach (Match item in matches) 10 { 11 Console.WriteLine(item.Value); 12 //提取好路径 13 string url = "http://localhost:8080/"+item.Groups[1].Value; 14 //下载 15 wc.DownloadFile(url,@"c:aa"+index.ToString()+".jpg"); 16 index++; 17 } 18 //wc.DownloadFile("",""); 19 Console.ReadKey(); 20 #endregion 我们可以试着把网页上的超链接抓取下来。 下面我们看下字符串的替换:
四十四、正则表达式替换 练习2:将连续的-都替换成一个- 234-----234--------------34------55 四十五、练习2答案 隐去手机号码的中间4位。 四十六、替换手机中间四位 细说,之前在工作的过程中,单位有个客服中心,那些孩子们每天都要打电话,系统里面的电话是全的,但是,要是用系统的导出功能,电话的中间4位就被替换了。当时,我们没怎么注意,当把电话理出来再打的时候,发现全是废号了。 苦逼程序员写出这样的程序,当时我真想骂娘。但是,转念想想,要是自己之前用过正则,就会留心去观察了。 练习1:将一段文本中的MM/DD/YYYY格式的日期转换为YYYY-MM-DD格式 ,比如“我的生日是05/21/2010耶”转换为“我的生日是2010-05-21耶”。 四十七、提取组练习 新加:热心同学提问 新加、两个$就显示$2 练习2:给一段文本中匹配到的url添加超链接,比如把http://www.test.com替换为<a href="http://www.test.com"> http://www.test.com</a>。参考代码见备注。因为这个是整体做为一个组,比较特殊,难以理解,先把日期转换的理解了就好理解了。 四十八、匹配到的url添加超链接练习 四十九、为什么乱码呢? 因为操作系统保存的utf-8,而在这里我们没有指定用utf-8,所以就乱了。现在网上都有指定编码的。 五十、指定编码了 五十一、指定编码 当然我们这么写非常的不规范。 五十二、这样就不乱码了 五十三、这样写也不乱吗了 练习1:将文本中连续的空格替换为一个空格. “hello welcome to China.”→”hello welcome to China” 第一个题跟我们之前做的一模一样。 练习2:给一个手机号码:13412345678,134****5678,用正则表达式Replace() 这个也已经演示过了。 练习3: zxh@itcast.cn→***@itcast.cn steve_zhao@163.com→**********@163.com sk@codeedu.com→**@codeedu.com 这个题按照我们目前的知识做还是有点困难。 把邮箱的前几位都替换成* 五十四、第一次替换 五十五、用委托这个重载 五十六、转到定义 五十七、这个类型 五十八、委托类型 要传个委托变量,什么样的变量才是委托变量呢?委托其实指向的是一个方法。这个方法必须跟委托匹配,返回值也得跟委托匹配。 五十九、用委托执行方法进行替换 我们通过这个案例,大家看到委托是,委托可以给一个方法变量,用委托才能存方法。 六十、效率不太高的写法 为了防止用户用恶意代码留言,大部分论坛都不允许使用HTML语句做为回帖内容(或者进行了转义),但是这限制了用户的发挥,比如用户无法粘贴超链接、无法粘贴图片地址,无法把自己发送的文字进行加粗,改变字号。为了解决这个问题,人们设计出了UBB代码,它提供了有限的、无危害的功能,用户只要遵循代码规则就可以实现用户想要的功能。UBB语法:http://baike.baidu.com/view/35.htm?fr=ala0_1_1。 六十一、这就是UBB代码 发布以后就变成html标签了。就是在用户编辑的时候不让用户发html标签,全让用户发UBB标签。 我们可以到http://www.wikipedia.org搜索这ubb。 接下来我们就完成ubb代码转换成html代码。 六十二、画好界面 六十三、替换代码 现在再看看这段代码是不是非常的轻松了呢? 六十四、ubb转换代码演示 最后我们再看下敏感词过滤 接下来我们就做个敏感词过滤 六十五、画好界面并添加敏感词 当我点发帖的时候要验证一下,有没有这个词,要是有这个词的话,提示一下用户。 观察一下我们为大家提供的词库,这部分我们已经放到下载里面,请大家下载。 有些词对应mod,有些词对应banned,一种需要审核,一种就需要禁止了。 能实现但是效率不高的C#代码插入位置:
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.IO; 10 11 namespace _03敏感词过滤 12 { 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 } 19 //1.加载敏感词到集合,分开存储 20 List<string> listMod = new List<string>(); 21 List<string> listBanned = new List<string>(); 22 private void btnSend_Click(object sender,EventArgs e) 23 { 24 //4.获取用户输入的帖子内容 25 string usrInput = txtContent.Text.Trim(); 26 //5.先判断用户输入的字符串中是否包含{BANNED}的关键词 27 bool b = false; 28 foreach (string item in listBanned) 29 { 30 if (usrInput.Contains(item)) 31 { 32 b = true; 33 break; 34 } 35 } 36 if (b) 37 { 38 MessageBox.Show("您输入的帖子内容中包含有【禁止发帖】的关键词,请检查!"); 39 } 40 else 41 { 42 //6.再检查有没有需要审核的关键词 43 foreach (string item in listMod) 44 { 45 if (usrInput.Contains(item)) 46 { 47 b = true; 48 break; 49 } 50 } 51 if (b) 52 { 53 MessageBox.Show("您的帖子需要经过审核,请等待!"); 54 } 55 else 56 { 57 MessageBox.Show("发帖成功!"); 58 } 59 } 60 61 } 62 63 private void Form1_Load(object sender,EventArgs e) 64 { 65 //2.当窗体加载的时候,填充集合 66 //把数据读取到列表里面,处理下编码的问题 67 string[] line = File.ReadAllLines("1.txt",Encoding.Default); 68 //3.循环判断分别加入集合 69 foreach (string item in line) 70 { 71 string[] parts = item.Split('='); 72 if (parts[1]=="{MOD}") 73 { 74 //表示该关键词需要审核 75 listMod.Add(parts[0]); 76 } 77 else if (parts[1]=="{BANNED}") 78 { 79 listBanned.Add(parts[0]); 80 } 81 } 82 } 83 } 84 } 六十六、能实现但是效率不高的C#代码演示 下面我们通过正则实现, 问题是,写个什么样的正则才能匹配任意的敏感词呢? 六十七、本身就是一个正则 通过正则实现敏感词过滤代码插入位置:
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.IO; 10 using System.Text.RegularExpressions; 11 12 namespace _03敏感词过滤 13 { 14 public partial class Form1 : Form 15 { 16 public Form1() 17 { 18 InitializeComponent(); 19 } 20 //1.加载敏感词到集合,分开存储 21 List<string> listMod = new List<string>(); 22 List<string> listBanned = new List<string>(); 23 private void btnSend_Click(object sender,EventArgs e) 24 { 25 26 #region 通过常规方式实现 27 28 29 ////4.获取用户输入的帖子内容 30 //string usrInput = txtContent.Text.Trim(); 31 ////5.先判断用户输入的字符串中是否包含{BANNED}的关键词 32 //bool b = false; 33 //foreach (string item in listBanned) 34 //{ 35 // if (usrInput.Contains(item)) 36 // { 37 // b = true; 38 // break; 39 // } 40 //} 41 //if (b) 42 //{ 43 // MessageBox.Show("您输入的帖子内容中包含有【禁止发帖】的关键词,请检查!"); 44 //} 45 //else 46 //{ 47 // //6.再检查有没有需要审核的关键词 48 // foreach (string item in listMod) 49 // { 50 // if (usrInput.Contains(item)) 51 // { 52 // b = true; 53 // break; 54 // } 55 // } 56 // if (b) 57 // { 58 // MessageBox.Show("您的帖子需要经过审核,请等待!"); 59 // } 60 // else 61 // { 62 // MessageBox.Show("发帖成功!"); 63 // } 64 //} 65 #endregion 66 67 #region 通过正则实现 68 string usrInput = txtContent.Text.Trim(); 69 string[] line = File.ReadAllLines("1.txt",Encoding.Default); 70 71 StringBuilder sbMod = new StringBuilder(); 72 StringBuilder sbBanned = new StringBuilder(); 73 foreach (string item in line) 74 { 75 string[] parts = item.Split('='); 76 if (parts[1]=="{MOD}") 77 { 78 sbMod.Append(parts[0]+"|"); 79 } 80 else if (parts[1]=="{BANNED}") 81 { 82 sbBanned.Append(parts[0]+"|"); 83 } 84 } 85 sbMod.Remove(sbMod.Length-1,1); 86 sbBanned.Remove(sbBanned.Length - 1,1); 87 string s1 = sbMod.ToString(); 88 string s2 = sbBanned.ToString(); 89 90 //直接用正则验证就行了 91 if (Regex.IsMatch(usrInput,s2)) 92 { 93 MessageBox.Show("包含禁止发帖的关键字"); 94 } 95 else if (Regex.IsMatch(usrInput,s1)) 96 { 97 MessageBox.Show("需要审核"); 98 } 99 else 100 { 101 MessageBox.Show("发帖成功"); 102 } 103 104 #endregion 105 } 106 107 private void Form1_Load(object sender,EventArgs e) 108 { 109 //2.当窗体加载的时候,填充集合 110 //把数据读取到列表里面,处理下编码的问题 111 string[] line = File.ReadAllLines("1.txt",Encoding.Default); 112 //3.循环判断分别加入集合 113 foreach (string item in line) 114 { 115 string[] parts = item.Split('='); 116 if (parts[1]=="{MOD}") 117 { 118 //表示该关键词需要审核 119 listMod.Add(parts[0]); 120 } 121 else if (parts[1]=="{BANNED}") 122 { 123 listBanned.Add(parts[0]); 124 } 125 } 126 } 127 } 128 } 如果要是发帖的人这样在 办证中间加个特殊符号,我们可以改下词库,办.{0,2}证 面试题:抓取招聘信息。 只抓取职位的超链接的href、标题,找职位超链接的“模式” http://search.51job.com/job/46629381,c.html,找规律。 使用开发人员工具,可能看到的源代码不准确。 原文地址http://www.cnblogs.com/zysbk/archive/2013/01/22/2847364.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |