Regex 類介紹 (C#)

mrhaozi發表於2010-03-24

Regex 類介紹

深入正規表示式

正規表示式(Regular expressions)是一套語法匹配規則,各種語言,如Perl, .Net和Java都有其對應的共享的正規表示式類庫。在.Net中,這個類庫叫做Regex。

簡單的說,Regex是從字元窗中查詢匹配字串的應用類。透過Regex,程式設計人員能夠非常方便的從一段資料中提取自己所需要的資料資訊。舉一個簡單的例子,讓大家對Regex有個大概的瞭解:

Regex regex = new Regex(@"d+");

Match m = regex.Match("fox 9212gold");

Console.WriteLine(m.Value.ToString());

結果很明顯,regex為我們找到了字串”fox 9212gold”中的數字字串,輸出結果為”9212” .

對Regex有了一個基本的概念之後,我需要告訴你一個非常好的訊息,那就是Regex可以為我們做的遠不止這麼一點點,他是一套功能非常強大語法匹配規則。當然,這裡還有一個壞訊息等著我們,那就是強大功能的語法規則自然需要大量紛繁複雜的keyword支援,這也為Regex的學習帶來了極大的難度。想要真正掌握正規表示式,可不是幾個sample能夠全部揭示與說明的。


建立一個Regex物件
Regex的建構函式有三種,在這裡就不討論預設建構函式了。另外兩個建構函式中,一個建構函式接收正規表示式字串作為入參,另一個以正規表示式字串和RegexOptions作為入參。如:

Regex regex = new Regex("w+$");

Regex regex = new Regex("s+", RegexOptions.IgnoreCase | RegexOptions.Multiline);

RegexOptions可以為我們提供一些特殊的幫助,比如IgnoreCase能夠在匹配是忽略大小寫,Multiline能夠調整^和$的意義,改為匹配一行的開頭和結尾。

上面我們構造了一個正規表示式,只不過我們還沒有用它來做任何事情,馬上我們就可以透過使用下面的幾個方法,實現對字串物件的操作了。

匹配字串
Regex有兩個獲取匹配的方法Match()和Matches(),分別代表匹配一個,匹配多個結果。這裡就用Matches來展示一下怎麼使用Regex獲取匹配字串,並將其顯示出來。

public static void showMatches(string expression, RegexOptions option, string ms)

{

Regex regex = new Regex(expression, option);

MatchCollection matches = regex.Matches(ms);

//show matches

Console.WriteLine("////////////////----------------------------------////////////////");

Console.WriteLine(" string: "{0}" expression: "{1}" match result is:",

ms, expression);

foreach(Match m in matches)

{ Console.WriteLine("match string is: "{0}", length: {1}",

m.Value.ToString(), m.Value.Length);

}

Console.WriteLine("matched count: {0}", matches.Count);

}


方法Matched透過比較入參字串和正規表示式,找到所有符合的結果,並將結果作為MatchCollection傳出來。這樣,只要簡單的遍歷這個collection,就可以很快的獲得所有的結果。


組的概念


當你獲得這樣的一個字串”最後比分是:19/24”,你肯定希望有一個正規表示式,他不單能夠找到形如 data1/data2的字串,還應該能夠直接把data1,data2作為單獨的結果傳送出來。否則你需要再對形如”19/24”的字串進行分析,才能夠順利得到雙方的比分。顯然,正規表示式不會忽略這個問題,所以他增加了組的概念。你可以把一次搜尋的結果分別放入不同的組中,並透過組名或者組的所以分別取得這些組的結果。比如上例,我們就可以用@”(d+)/(d+)”作為表示式。來看看結果吧:

Regex regex = new Regex(@"(d+)/(d+)");

MatchCollection matches = regex.Matches(@"最後比分是:19/24");

//show matches

Console.WriteLine("////////////////----------------------------------////////////////");

foreach(Match m in matches)

{

//Console.WriteLine("match string is: "{0}", length: {1}", // m.Value.ToString(), m.Value.Length);

foreach(string name in regex.GetGroupNames())

{

Console.WriteLine(" capture group "{0}" value is:"{1}""

, name, m.Groups[name].Value);

}

}

Console.WriteLine("matched count: {0}", matches.Count);


輸出:

////////////////----------------------------------////////////////

capture group "0" value is:"19/24"

capture group "1" value is:"19"

capture group "2" value is:"24"

matched count: 1


現在清楚了吧,Regex物件把匹配的結果放入組0中。同時,匹配的組資訊也放入了對應的組中。組的名稱在預設的情況下,是從1開始依次增加的整數。0作為保留名稱,專門用於指示匹配的整個字串。既然有”預設情況”這樣的概念,自然也就意味著使用者可以自定義組的名稱。方法很簡單,在組的前面加上:?就可以了。好了,現在把前面的正規表示式修改一下,換成@”(?d+)/(?d+)”,現在再看看結果:

////////////////----------------------------------////////////////

capture group "0" value is:"19/24"

capture group "score1" value is:"19"

capture group "score2" value is:"24"

matched count: 1


換成自己定義的名字了吧,哈哈!為了在今後的測試中,能夠更加方便的看到所有結果,我們對前面介紹過的showMatches()做一點小小的調整。這樣,如果在表示式中包含了組的定義,我們也可以在不需要修改任何程式碼的情況下,直接看到所有的組資訊了,調整後的方法showMatchesPro()如下:

public static void showMatchesPro(string expression, RegexOptions option, string ms)

{

Regex regex = new Regex(expression, option);

MatchCollection matches = regex.Matches(ms);

//show matches

Console.WriteLine("////////////////----------------------------------////////////////");

Console.WriteLine(" string: "{0}" expression: "{1}" match result is:",

ms, expression);

foreach(Match m in matches)

{ foreach(string name in regex.GetGroupNames())

{

Console.WriteLine(" capture group "{0}" value is:"{1}"",

name, m.Groups[name].Value);

}

}

Console.WriteLine("matched count: {0}", matches.Count);

// show group name

Console.WriteLine("group name count {0}", regex.GetGroupNames().Length);

foreach(string name in regex.GetGroupNames())

{

Console.WriteLine("group name :"{0}"", name);

}

}


替換字串
Regex也提供了方便的匹配結果替換的功能。為了方便測試,我們也把他寫成方法,程式碼如下:

public static string replaceMatch(string expression, RegexOptions option, string ms, string rep)

{

Regex regex = new Regex(expression, option);

string result = regex.Replace(ms, rep);

Console.WriteLine("////////////////----------------------------------////////////////");

Console.WriteLine("string: "{0}", expression:"{1}", replace by : "{2}"",

ms, expression, rep);

Console.WriteLine("replace result string is: "{0}", length: {1}",

result.ToString(), result.Length);

return result;

}


Regex.Replace通常接受兩個string作為入參,第一個string為輸入字串。第二個字串用來替代匹配字串,它可以包含一些特殊字串,用來代表特別轉換。


特殊字串 替換結果

$& 匹配的字串,也可以用$0

$1, $2, . . . 匹配字串中的對應組,用索引標示

${name} 匹配字串中的對應組,用名稱標示

$‘ 匹配位置之前的字串

$’ 匹配位置之後的字串

$$ 一個‘$’ 字元

$_ 輸入字串

$+ 匹配字串的所有組中,最後一個組中的資料


是不是看了這麼多怪型怪狀的特殊字串,有點頭暈了?嗯,那就弄兩個sample來看看結果吧!

Sample1:

replaceMatch(@"d+", RegexOptions.None, "fef 12/21 df 33/14 727/1", "<>");

輸出,所有數字型的資料都被替換成了<>:

////////////////----------------------------------////////////////

string: "fef 12/21 df 33/14 727/1", expression:"d+", replace by : "<>"

replace result string is: "fef <<12>>/<<21>> df <<33>>/<<14>> <<727>>/<<1>>",

length: 50


Sample2:

replaceMatch(@"(d+)/(d+)", RegexOptions.None, "fef 12/21 df 33/14 727/1", "$+");

輸出,所有data1/data2匹配的資料,都被替換成了data2:

////////////////----------------------------------////////////////

string: "fef 12/21 df 33/14 727/1", expression:"(d+)/(d+)", replace by : "$+"

replace result string is: "fef 21 df 14 1", length: 16


怎麼樣,Regex的功能夠豐富的吧!可是,也許你的需求不光這麼簡單,比如說,你要把”I have 200 dollars”中間的money加倍,怎麼辦?我暈倒,好像沒有現成的東西可以用。沒有關係,Regex還有更好的功能。它允許你自己定義轉換公式。

using System.Text.RegularExpressions;

class RegularExpressions

{

static string CapText(Match m)

{

// Get the matched string.

string x = m.ToString();

// double this value

string result = (int.Parse(x) * 2).ToString();

return result;

}

static void Main()

{

string text = "i have 200 dollars";

string result = Regex.Replace(text, @"d+",

new MatchEvaluator(RegularExpressions.CapText));

System.Console.WriteLine("result=[" + result + "]");

}

}


看看結果,太好了,我的錢真的變成了兩倍!

但本文的目的是希望提供給大家一個方便好用的測試類,因此我們過載上面的repalceMatch方法,也允許自定義轉換公式作為入參:

public static string replaceMatch(string expression, RegexOptions option, string ms,

MatchEvaluator evaluator)

{

Regex regex = new Regex(expression, option);

string result = regex.Replace(ms, evaluator);

Console.WriteLine("////////////////----------------------------------////////////////");

Console.WriteLine("string: "{0}", expression:"{1}", replace by a evaluator.", ms,

expression);

Console.WriteLine("replace result string is: "{0}", length: {1}", result.ToString(),

result.Length);

return result;

}


拆分字串


Regex還提供了從匹配位置將字串拆分的方法Split。這個方法同樣具有多個過載,不過這些都不是重點,大家可以自己看文件。我們繼續完成我們用於測試的方法:

public static void splitMatch(string expression, RegexOptions option, string ms)

{

Regex regex = new Regex(expression, option);

string[] result = regex.Split(ms);

Console.WriteLine("////////////////----------------------------------////////////////");

Console.WriteLine("string: "{0}", expression: "{1}", split result is:", ms,

expression);

foreach(string m in result)

{

Console.WriteLine("splited string is: "{0}", length: {1}",

m.ToString(), m.Length);

}

Console.WriteLine("splited count: {0}", result.Length);

}

程式碼簡單,不多做解釋。直接來一個smaple看看結果:

splitMatch(@"/",RegexOptions.None, "2004/4/25");

輸出:

////////////////----------------------------------////////////////

string: "2004/4/25", expression: "/", split result is:

splited string is: "2004", length: 4

splited string is: "4", length: 1

splited string is: "25", length: 2

splited count: 3


這個文章的目的很簡單:介紹Regex的幾個主要功能(匹配、替換和拆分),並提供幾個簡單方便的測試函式。讓你能夠測試你對正規表示式的理解是否準確。


比如想要確認^$的作用,你可以放入這樣的(input, expression)資料:

(“123”, “^d+$”) (“123aaa456”, “^d+”) (“123aaa456”, “123&”)


確認d, s, w, W的作用,可以這樣測試:

(“123abc gc 456”, “d+”)(“123abc gc 456”, “s+”)

(“123abc gc 456”, “w+”)(“123abc gc 456”, “W+”)


比較? + *之間的區別可以用這樣的資料:

(“a123 abcd”, “ad?”) (“a123 abcd”, “ad+”) (“a123 abcd”, “ad*”)

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16396910/viewspace-1032282/,如需轉載,請註明出處,否則將追究法律責任。

相關文章