[C#] 正則表達(dá)式

正則表達(dá)式是判斷栖袋、匹配和分解一定模式的字符串的法寶。C#強(qiáng)大的基礎(chǔ)類庫(kù)提供的System.Text.RegularExpressions命名空間里包含的Regex類,可以充分發(fā)揮正則表達(dá)式的威力吟榴。

需要查看C#中正則表達(dá)式里各個(gè)符號(hào)的意義的請(qǐng)查閱這里,不過(guò)看一遍也很難記住囊扳,可以用的時(shí)候再查詢吩翻,用的次數(shù)多了就會(huì)記住那些使用頻率較高的符號(hào)了。

0. 簡(jiǎn)單介紹C#里Regex類的用法

(1)檢查一個(gè)字符串是否符合指定的模式宪拥,如pattern="^[0-9]*$"

Regex regex = new Regex(pattern);
if (regex.IsMatch(test)) 
  Console.WriteLine("{0} matches the pattern.", test); 
else Console.WriteLine("{0} does not match the pattern.", test);

(2)提取一定模式的字符串

Match match = regex.Match(text);
MatchCollection matches = regex.Matches(text);

如果能夠確定text里面只有一個(gè)子串滿足模式pattern仿野,可以用Match;如果可能有多個(gè)匹配她君,則可以使用Matches脚作。當(dāng)然若我們只需要從包含多個(gè)pattern的text中找到第一個(gè),那么也可以用Match
Match中兩個(gè)重要的屬性是ValueIndex球涛,其中Value為滿足設(shè)定模式的子串劣针,Index為該子串在輸入字符串中的開(kāi)始位置。
另外亿扁,如果我們匹配的模式中有多個(gè)項(xiàng)捺典,如"\b(?<word>\w+)\s+(\k<word>)\b"表示重復(fù)的單詞,它的模式串中有兩個(gè)word从祝,我們最后得到的Match.Value可能是“dog dog”襟己,而若我們想得到單個(gè)單詞的話還需要進(jìn)一步對(duì)這個(gè)子串進(jìn)行劃分。但是Match中還有一個(gè)重要的屬性已經(jīng)幫我們做好了這一步牍陌,Match.Groups獲取由正則表達(dá)式匹配的組的集合擎浴,對(duì)于上面的例子Match.Groups["word"].Value就表示“dog”。

Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
string text = "The the quick brown fox  fox jumped over the lazy dog dog.";

Match singleMatch = rx.Match(text);
Console.WriteLine("Value: {0}", singleMatch.Value);
Console.WriteLine("Index: {0}", singleMatch.Index);

MatchCollection matches = rx.Matches(text);
foreach (Match match in matches)
{
    GroupCollection groups = match.Groups;
    Console.WriteLine("'{0}' repeated at positions {1} and {2}",
                       groups["word"].Value,
                       groups[0].Index,
                       groups[1].Index);
 }

(3)替換匹配的子串
string replactedText = rx.Replace(text, myEvaluator);
這里的參數(shù)myEvaluatorMatchEvaluator委托。下面的例子中我們專門(mén)定義了方法ReplaceCC2C()來(lái)將重復(fù)出現(xiàn)的單詞去掉一個(gè)(即替換成單個(gè)單詞)。MatchEvaluator委托的輸入是Match做瞪,輸出是要替換Match.Value的字符串。
如果替換的方法比較簡(jiǎn)單時(shí)仿吞,我們可以省去專門(mén)定義一個(gè)方法的力氣,直接使用匿名方法捡偏,如

var test = rx.Replace(text, delegate(Match m) { return m.Groups["word"].Value; });
public void ExtractMatches()
{
    Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    string text = "The the quick brown fox  fox jumped over the lazy dog dog.";

    RegexExample ex = new RegexExample();
    MatchEvaluator myEvaluator = new MatchEvaluator(ex.ReplaceCC2C);
    var replactedText = rx.Replace(text, myEvaluator);
    //var replactedText = rx.Replace(text, delegate(Match m) { return m.Groups["word"].Value; });
    Console.WriteLine(text);
    Console.WriteLine(replactedText);
}

public string ReplaceCC2C(Match m)
{
    return m.Groups["word"].Value;
}

輸出結(jié)果:

The the quick brown fox  fox jumped over the lazy dog dog.
The quick brown fox jumped over the lazy dog.

(4)拆分字符串
string[] parts = rx.Split(text);
雖然C#string也有Split函數(shù)唤冈,但是它的參數(shù)只能是確定的字符數(shù)組,而RegexSplit函數(shù)則是利用正則表達(dá)式模式將輸入字符串拆分成子字符串?dāng)?shù)組霹琼。

下面我們從一些常見(jiàn)的例子來(lái)嘗試使用正則表達(dá)式务傲,上面已經(jīng)介紹的Regex的用法,下面的例子都是檢查是否滿足某模式串枣申,都是用IsMatch售葡,所以接下來(lái)我只會(huì)列出模式串。

1. 驗(yàn)證我國(guó)的座機(jī)電話號(hào)碼

首先我們列出所有想要支持的電話號(hào)碼的格式忠藤,然后再分類看怎么寫(xiě)正則表達(dá)式挟伙。
規(guī)則:我國(guó)的座機(jī)號(hào)碼分為區(qū)號(hào)和號(hào)碼,區(qū)號(hào)與號(hào)碼之間用短橫‘-’或者括號(hào)‘()’來(lái)分割模孩,另外最前面還可能會(huì)加上我國(guó)的區(qū)號(hào)86或者+86尖阔,下面列舉出一些合法的電話號(hào)碼:
027-88888888
0722-7777777
(027)88888888
(0722)7777777
86(027)88888888
+86(0722)7777777
所以最后寫(xiě)出的表達(dá)式為:
"^(\+)?(86)?0\d{2,3}-\d{7,8}$|^(\+)?(86)?\(0\d{2,3}\)\d{7,8}$"

另外,我看到有人這樣寫(xiě)"0\d{2,3}-\d{7,8}|\(0\d{2,3}\)\d{7,8}"榨咐,雖然上面的例子都能通過(guò)介却,但是它可能會(huì)使得027-888888889999也是合法的,因?yàn)樯鲜霰磉_(dá)式是在輸入字符串里找到一個(gè)子串滿足我們的模式要求块茁,只要存在這樣的子串IsMatch就會(huì)返回true齿坷。所以我們需要在對(duì)模式串加上開(kāi)始字符^和結(jié)束字符$來(lái)避免這種情況桂肌。

2. 驗(yàn)證手機(jī)電話號(hào)碼

規(guī)則
手機(jī)號(hào)碼為11位數(shù)字,首位一定是1永淌,到目前為止第二位數(shù)字可以是3,4,5,7,8崎场,其他位可以是0-9的任意數(shù)字。格式上可以是所有數(shù)字連寫(xiě)遂蛀,也可以在中間加上短橫分割谭跨。
正例
13012345678
15887654321
178-23760930
178-2376-0930
反例
1301234567
158876543212
178-2376-0930-
正則表達(dá)式"^1[34578]+\d{1}((-)?\d{4}){2}$"
逐字符解釋^表示電話號(hào)碼的開(kāi)始,1表示第一位字符一定要是1李滴,[34578]+表示第二位字符是3,4,5,7,8中的至少一個(gè)螃宙,\d{1}表示一個(gè)數(shù)字,同理\d{4}表示4個(gè)數(shù)字悬嗓,(-)?表示短橫可以出現(xiàn)0次或1次污呼,((-)?\d{4}){2}表示(-)?\d{4}出現(xiàn)兩次,$表示電話號(hào)碼結(jié)束包竹。

3. 驗(yàn)證電子郵箱

規(guī)則:必須以字母開(kāi)始(有人說(shuō)有郵箱可以以下劃線開(kāi)始,比如說(shuō)Yahoo籍凝,但是我專門(mén)去注冊(cè)試了試周瞎,人家要求一定要以字母開(kāi)始);電子郵箱中包含且僅包含一個(gè)@字符饵蒂,該字符將郵箱劃分為兩個(gè)部分声诸;前部分為用戶名,可以由字母退盯、數(shù)字彼乌、下劃線、短橫或點(diǎn)組成渊迁;不能出現(xiàn)多個(gè)短橫或點(diǎn)相連的情況慰照;
正例
12345@qq.com
test.Name@163.com
full_name@google.com
__12-345@qq.com
反例
__12--345@qq.com
正則表達(dá)式"^[A-Za-z]+([-.]\w+)*@\w+([-.]\w+)*\.[a-z]{2,3}$"
逐字符解釋^[A-Za-z]+表示至少有一個(gè)字母,\w+表示至少一個(gè)包括下劃線的任何單詞字符琉朽,等價(jià)于[A-Za-z0-9_]+毒租,([-.]\w+)*表示零個(gè)或者多個(gè)[-.]\w+,而[-.]\w+表示-或者.加上包括下劃線的任何單詞字符箱叁,這樣寫(xiě)正好可以把多個(gè)短橫或者點(diǎn)號(hào)用字符分隔開(kāi)墅垮,@字符后面的前半部分與之前的類似,最后一部分為\.[a-z]{2,3}耕漱,表示后綴為.加上2個(gè)或者2個(gè)小寫(xiě)字母算色。
:有人可能會(huì)說(shuō)qq郵箱前面應(yīng)該全部都是數(shù)字,所以上面的表達(dá)式不松了螟够。這就看大家的使用環(huán)境了灾梦,比如說(shuō)有些郵箱對(duì)用戶名的長(zhǎng)度也有限制,所以還是不要想一勞永逸了吧。只要在使用的時(shí)候把應(yīng)用場(chǎng)景下的所有情況列舉出來(lái)斥废,能夠滿足要求即可椒楣。

4. 驗(yàn)證身份證號(hào)碼

規(guī)則:早期的身份證號(hào)碼是15位的全數(shù)字;現(xiàn)在的身份證號(hào)碼為18位牡肉,由17位數(shù)字和1位校驗(yàn)字符組成捧灰;最后的校驗(yàn)字符可能0-10,其中10由字母X或者x表示统锤。
正例
429001197806281
429001197806281234
42900119780628123X
42900119780628123x
反例
42900119780628123a
4290011978062812
4290011978062812345
正則表達(dá)式"^\d{15}$|^\d{18}$|^\d{17}[Xx]+$"
逐字符解釋:以上分了三種情況毛俏,\d{15}表示15位數(shù)字,\d{17}[Xx]+表示17位數(shù)字再加上一位X或者x饲窿。
:其實(shí)現(xiàn)在身份證上的前面17位數(shù)字也不是任意的0-9的數(shù)字煌寇,比如說(shuō)出生日期里的年月日都應(yīng)該是有限制的,上述表達(dá)式并沒(méi)有嚴(yán)格考慮這些逾雄,大家根據(jù)需要增加更嚴(yán)格的驗(yàn)證阀溶。

5. 驗(yàn)證IP地址

規(guī)則:點(diǎn)分十進(jìn)制的IPV4地址,格式為X.X.X.X鸦泳,其中X為0-255银锻。
正例
127.0.0.1
255.255.255.255
0.0.0.0
248.250.198.23
反例
256.0.0.0
00.0.0.1
127.012.032.1234
正則表達(dá)式"^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)$"
逐字符解釋:為了更好地表示IP地址中對(duì)數(shù)字的限制,這里我們將0-255劃分成了多個(gè)區(qū)段250-255,240-249,100-199,10-99,0-9

小結(jié)一些常見(jiàn)的模式

^做鹰,匹配字符串的開(kāi)始
\d击纬,用來(lái)匹配0到9的數(shù)字
\w,用來(lái)匹配字母數(shù)字或者下劃線
(xx)?钾麸,用來(lái)表示xx出現(xiàn)零次或者一次
(xx)+更振,用來(lái)表示xx至少出現(xiàn)一次
(xx)*,用來(lái)表示xx出現(xiàn)零次或者多次
(xx){2,3}饭尝,用來(lái)表示xx出現(xiàn)兩次或者三次
[123abc]肯腕,其中[]用來(lái)表示里面出現(xiàn)的字符是或的關(guān)系
$,匹配字符串的結(jié)束

參考文獻(xiàn):

  1. Regex 類
  2. C#中正則表達(dá)式的使用
  3. C#正則表達(dá)式Regex類的用法
  4. C#正則表達(dá)式語(yǔ)法大全
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芋肠,一起剝皮案震驚了整個(gè)濱河市乎芳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帖池,老刑警劉巖奈惑,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異睡汹,居然都是意外死亡肴甸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)囚巴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)原在,“玉大人友扰,你說(shuō)我怎么就攤上這事∈粒” “怎么了村怪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浮庐。 經(jīng)常有香客問(wèn)我甚负,道長(zhǎng),這世上最難降的妖魔是什么审残? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任梭域,我火速辦了婚禮,結(jié)果婚禮上搅轿,老公的妹妹穿的比我還像新娘病涨。我一直安慰自己,他們只是感情好璧坟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布既穆。 她就那樣靜靜地躺著,像睡著了一般沸柔。 火紅的嫁衣襯著肌膚如雪循衰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天褐澎,我揣著相機(jī)與錄音,去河邊找鬼伐蒋。 笑死工三,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的先鱼。 我是一名探鬼主播俭正,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼焙畔!你這毒婦竟也來(lái)了掸读?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宏多,失蹤者是張志新(化名)和其女友劉穎儿惫,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體伸但,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肾请,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了更胖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铛铁。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隔显,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饵逐,到底是詐尸還是另有隱情括眠,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布倍权,位于F島的核電站掷豺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏账锹。R本人自食惡果不足惜萌业,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奸柬。 院中可真熱鬧生年,春花似錦、人聲如沸廓奕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)桌粉。三九已至蒸绩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铃肯,已是汗流浹背患亿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留押逼,地道東北人步藕。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像挑格,于是被迫代替她去往敵國(guó)和親咙冗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容