C# 正則表達(dá)式,你會(huì)幾個(gè)?
本文轉(zhuǎn)載自微信公眾號(hào)「CSharp編程大全」,作者 zls365 。轉(zhuǎn)載本文請(qǐng)聯(lián)系CSharp編程大全公眾號(hào)。
最近寫爬蟲時(shí)需要用到正則表達(dá)式,有段時(shí)間沒有使用正則表達(dá)式現(xiàn)在漸漸感覺有些淡忘,現(xiàn)在使用還需要去查詢一些資料。為了避免以后這樣的情況,在此記錄下正則表達(dá)式的一些基本使用方法附帶小的實(shí)例。讓以后在使用時(shí)能一目了然知道他的使用,為開發(fā)節(jié)約時(shí)間,同時(shí)也分享給大家。
正則元字符
在說正則表達(dá)式之前我們先來看看通配符,我想通配符大家都用過。通配符主要有星號(hào)(*)和問號(hào)(?),用來模糊搜索文件。winodws中我們常會(huì)使用搜索來查找一些文件。如:*.jpg,XXX.docx的方式,來快速查找文件。其實(shí)正則表達(dá)式和我們通配符很相似也是通過特定的字符匹配我們所要查詢的內(nèi)容信息。已下代碼都是區(qū)分大小寫。
常用元字符
懶惰限定符
捕獲分組
得到上面秘籍后我們可以小試牛刀...
小試牛刀
在C#中使用正則表達(dá)式主要是通過Regex類來實(shí)現(xiàn)。命名空間:using System.Text.RegularExpressions。
其中常用方法:
在使用正則表達(dá)式前我們先來看看“@”符號(hào)的使用。
學(xué)過C#的人都知道C# 中字符串常量可以以@ 開頭聲名,這樣的優(yōu)點(diǎn)是轉(zhuǎn)義序列“不”被處理,按“原樣”輸出,即我們不需要對(duì)轉(zhuǎn)義字符加上 \ (反斜扛),就可以輕松coding。如:
- string filePath = @"c:\Docs\Source\CK.txt" // rather than "c:\\Docs\\Source\\CK.txt"
如要在一個(gè)用 @ 引起來的字符串中包括一個(gè)雙引號(hào),就需要使用兩對(duì)雙引號(hào)了。這時(shí)候你不能使用 \ 來轉(zhuǎn)義爽引號(hào)了,因?yàn)樵谶@里 \ 的轉(zhuǎn)義用途已經(jīng)被 @ “屏蔽”掉了。如:
- string str=@"""Ahoy!"" cried the captain." // 輸出為:"Ahoy!" cried the captain.
字符串匹配:
在實(shí)際項(xiàng)目中我們常常需要對(duì)用戶輸入的信息進(jìn)行驗(yàn)證。如:匹配用戶輸入的內(nèi)容是否為數(shù)字,是否為有效的手機(jī)號(hào)碼,郵箱是否合法....等。
實(shí)例代碼:
- string RegexStr = string.Empty;
- #region 字符串匹配
- RegexStr = "^[0-9]+$"; //匹配字符串的開始和結(jié)束是否為0-9的數(shù)字[定位字符]
- Console.WriteLine("判斷'R1123'是否為數(shù)字:{0}", Regex.IsMatch("R1123", RegexStr));
- Console.WriteLine("判斷'1123'是否為數(shù)字:{0}", Regex.IsMatch("1123", RegexStr));
- RegexStr = @"\d+"; //匹配字符串中間是否包含數(shù)字(這里沒有從開始進(jìn)行匹配噢,任意位子只要有一個(gè)數(shù)字即可)
- Console.WriteLine("'R1123'是否包含數(shù)字:{0}", Regex.IsMatch("R1123", RegexStr));
- Console.WriteLine("'博客園'是否包含數(shù)字:{0}", Regex.IsMatch("博客園", RegexStr));
- //感謝@zhoumy的提醒..已修改錯(cuò)誤代碼
- RegexStr = @"^Hello World[\w\W]*"; //已Hello World開頭的任意字符(\w\W:組合可匹配任意字符)
- Console.WriteLine("'HeLLO WORLD xx hh xx'是否已Hello World開頭:{0}", Regex.IsMatch("HeLLO WORLD xx hh xx", RegexStr, RegexOptions.IgnoreCase));
- Console.WriteLine("'LLO WORLD xx hh xx'是否已Hello World開頭:{0}", Regex.IsMatch("LLO WORLD xx hh xx", RegexStr,RegexOptions.IgnoreCase));
- //RegexOptions.IgnoreCase:指定不區(qū)分大小寫的匹配。
- #endregion
顯示結(jié)果:
字符串查找:
實(shí)例代碼:
- string RegexStr = string.Empty;
- #region 字符串查找
- string LinkA = "<a href=\"http://www.baidu.com\" target=\"_blank\">百度</a>";
- RegexStr = @"href=""[\S]+"""; // ""匹配"
- Match mt = Regex.Match(LinkA, RegexStr);
- Console.WriteLine("{0}。", LinkA);
- Console.WriteLine("獲得href中的值:{0}。", mt.Value);
- RegexStr = @"<h[^23456]>[\S]+<h[1]>"; //<h[^23456]>:匹配h除了2,3,4,5,6之中的值,<h[1]>:h匹配包含括號(hào)內(nèi)元素的字符
- Console.WriteLine("{0}。GetH1值:{1}", "<H1>標(biāo)題<H1>", Regex.Match("<H1>標(biāo)題<H1>", RegexStr, RegexOptions.IgnoreCase).Value);
- Console.WriteLine("{0}。GetH1值:{1}", "<h2>小標(biāo)<h2>", Regex.Match("<h2>小標(biāo)<h2>", RegexStr, RegexOptions.IgnoreCase).Value);
- //RegexOptions.IgnoreCase:指定不區(qū)分大小寫的匹配。
- RegexStr = @"ab\w+|ij\w{1,}"; //匹配ab和字母 或 ij和字母
- Console.WriteLine("{0}。多選結(jié)構(gòu):{1}", "abcd", Regex.Match("abcd", RegexStr).Value);
- Console.WriteLine("{0}。多選結(jié)構(gòu):{1}", "efgh", Regex.Match("efgh", RegexStr).Value);
- Console.WriteLine("{0}。多選結(jié)構(gòu):{1}", "ijk", Regex.Match("ijk", RegexStr).Value);
- RegexStr = @"張三?豐"; //?匹配前面的子表達(dá)式零次或一次。
- Console.WriteLine("{0}。可選項(xiàng)元素:{1}", "張三豐", Regex.Match("張三豐", RegexStr).Value);
- Console.WriteLine("{0}。可選項(xiàng)元素:{1}", "張豐", Regex.Match("張豐", RegexStr).Value);
- Console.WriteLine("{0}??蛇x項(xiàng)元素:{1}", "張飛", Regex.Match("張飛", RegexStr).Value);
- /*
- 例如:
- July|Jul 可縮短為 July?
- 4th|4 可縮短為 4(th)?
- */
- //匹配特殊字符
- RegexStr = @"Asp\.net"; //匹配Asp.net字符,因?yàn)?是元字符他會(huì)匹配除換行符以外的任意字符。這里我們只需要他匹配.字符即可。所以需要轉(zhuǎn)義\.這樣表示匹配.字符
- Console.WriteLine("{0}。匹配Asp.net字符:{1}", "Java Asp.net SQLServer", Regex.Match("Java Asp.net SQLServer", RegexStr).Value);
- Console.WriteLine("{0}。匹配Asp.net字符:{1}", "C# Java", Regex.Match("C# Java", RegexStr).Value);
- #endregion
顯示結(jié)果:
貪婪與懶惰
- string f = "fooot";//貪婪匹配
- RegexStr = @"f[o]+";
- Match m1 = Regex.Match(f, RegexStr);
- Console.WriteLine("{0}貪婪匹配(匹配盡可能多的字符):{1}", f, m1.ToString());
- //懶惰匹配
- RegexStr = @"f[o]+?";
- Match m2 = Regex.Match(f, RegexStr);
- Console.WriteLine("{0}懶惰匹配(匹配盡可能少重復(fù)):{1}", f, m2.ToString());
顯示結(jié)果:
從上面的例子中我們不難看出貪婪與懶惰的區(qū)別,他們的名子取的都很形象。
貪婪匹配:匹配盡可能多的字符。
懶惰匹配:匹配盡可能少的字符。
(exp)分組
在做爬蟲時(shí)我們經(jīng)常獲得A中一些有用信息。如href,title和顯示內(nèi)容等。
- string TaobaoLink = "<a href=\"http://www.taobao.com\" title=\"淘寶網(wǎng) - 淘!我喜歡\" target=\"_blank\">淘寶</a>";
- RegexStr = @"<a[^>]+href=""(\S+)""[^>]+title=""([\s\S]+?)""[^>]+>(\S+)</a>";
- Match mat = Regex.Match(TaobaoLink, RegexStr);
- for (int i = 0; i < mat.Groups.Count; i++)
- {
- Console.WriteLine("第"+i+"組:"+mat.Groups[i].Value);
- }
顯示結(jié)果:
在正則表達(dá)式里使用()包含的文本自動(dòng)會(huì)命名為一個(gè)組。上面的表達(dá)式中共使用了4個(gè)()可以認(rèn)為是分為了4組。
輸出結(jié)果共分為:4組。
0組:為我們所匹配的字符串。
1組:是我們第一個(gè)括號(hào)[href=""(\S+)""]中(\S+)所匹配的網(wǎng)址信息。內(nèi)容為:http://www.taobao.com。
2組:是第二個(gè)括號(hào)[title=""([\s\S]+?)""]中所匹配的內(nèi)容信息。內(nèi)容為:淘寶網(wǎng) - 淘!我喜歡。
這里我們會(huì)看到+?懶惰限定符。title=""([\s\S]+?)"" 這里+?的下一個(gè)字符為"雙引號(hào),"雙引號(hào)在匹配字符串后面還有三個(gè)。+?懶惰限定符會(huì)盡可能少重復(fù),所他會(huì)匹配最前面那個(gè)"雙引號(hào)。如果我們不使用+?懶惰限定符他會(huì)匹配到:淘寶網(wǎng) - 淘!我喜歡" target= 會(huì)盡可能多重復(fù)匹配。
3組:是第三個(gè)括號(hào)[(\S+)]所匹配的內(nèi)容信息。內(nèi)容為:淘寶。
說明:反義元字符所對(duì)應(yīng)的元字符都能組合匹配任意字符。如:[\w\W],[\s\S],[\d\D]..
(?<name>exp) 分組取名
當(dāng)我們匹配分組信息過多后,在某種場(chǎng)合只需取當(dāng)中某幾組信息。這時(shí)我們可以對(duì)分組取名。通過分組名稱來快速提取對(duì)應(yīng)信息。
- string Resume = "基本信息姓名:CK|求職意向:.NET軟件工程師|性別:男|學(xué)歷:本專|出生日期:1988-08-08|戶籍:湖北.孝感|E - Mail:9245162@qq.com|手機(jī):15000000000";
- RegexStr = @"姓名:(?<name>[\S]+)\|\S+性別:(?<sex>[\S]{1})\|學(xué)歷:(?<xueli>[\S]{1,10})\|出生日期:(?<Birth>[\S]{10})\|[\s\S]+手機(jī):(?<phone>[\d]{11})";
- Match matc = Regex.Match(Resume, RegexStr);
- Console.WriteLine("姓名:{0},手機(jī)號(hào):{1}", matc.Groups["name"].ToString(), matc.Groups["phone"].ToString());
顯示結(jié)果:
通過(?<name>exp)可以很輕易為分組取名。然后通過Groups["name"]取得分組值。
獲得頁面中A標(biāo)簽中href值
- string PageInfo = @"<hteml>
- <div id=""div1"">
- <a href=""http://www.baidu.con"" target=""_blank"">百度</a>
- <a href=""http://www.taobao.con"" target=""_blank"">淘寶</a>
- <a href=""http://www.cnblogs.com"" target=""_blank"">博客園</a>
- <a href=""http://www.google.con"" target=""_blank"">google</a>
- </div>
- <div id=""div2"">
- <a href=""/zufang/"">整租</a>
- <a href=""/hezu/"">合租</a>
- <a href=""/qiuzu/"">求租</a>
- <a href=""/ershoufang/"">二手房</a>
- <a href=""/shangpucz/"">商鋪出租</a>
- </div>
- </hteml>";
- RegexStr = @"<a[^>]+href=""(?<href>[\S]+?)""[^>]*>(?<text>[\S]+?)</a>";
- MatchCollection mc = Regex.Matches(PageInfo, RegexStr);
- foreach (Match item in mc)
- {
- Console.WriteLine("href:{0}--->text:{1}",item.Groups["href"].ToString(),item.Groups["text"].ToString());
- }
顯示結(jié)果:
Replace 替換字符串
用戶在輸入信息時(shí)偶爾會(huì)包含一些敏感詞,這時(shí)我們需要替換這個(gè)敏感詞。
- string PageInputStr = "靠.TMMD,今天真不爽....";
- RegexStr = @"靠|TMMD|媽的";
- Regex rep_regex = new Regex(RegexStr);
- Console.WriteLine("用戶輸入信息:{0}", PageInputStr);
- Console.WriteLine("頁面顯示信息:{0}", rep_regex.Replace(PageInputStr, "***"));
顯示結(jié)果:
對(duì)一些敏感詞直接替換成***代替。
Split 拆分字符串
- string SplitInputStr = "1xxxxx.2ooooo.3eeee.4kkkkkk.";
- RegexStr = @"\d";
- Regex spl_regex = new Regex(RegexStr);
- string[] str = spl_regex.Split(SplitInputStr);
- foreach (string item in str)
- {
- Console.WriteLine(item);
- }
顯示結(jié)果:
根據(jù)數(shù)字截取字符串。