asp教程.net c# 學用的Regex
一、組的分類
正則中的組有擷取的群組和非擷取的群組,而擷取的群組又分為普通的擷取的群組和命名擷取的群組,分別為
擷取的群組:(exp)
命名擷取的群組:(? <name> exp)
非擷取的群組:(?:exp)
二、組的作用
1、擷取的群組的作用
擷取的群組的作用是將Regexexp匹配到的內容儲存到組裡,供以後使用
比如這樣一個字串:
<a href="http://anmo./" title="床上等你"> csdn </a>
我想得到網址,而它符合的規則是在 <a...> 標籤內,那就可以這樣做
c# code
string test = "<a href="http://anmo./" title="床上等你">csdn</a>";
match m = regex.match(test, @"<as*href=""([^""]*)""[^>]*>", regexoptions.ignorecase);
if (m.success)
messagebox.show(m.groups教程[1].value);
上面的Regex匹配到了 <a href="http://anmo./" title="床上等你"> ,而我們想得到網址,運算式其它部分只是為了保證取到的網址是在 <a...> 標籤內的,所以這裡用到的擷取的群組,把匹配到的網址儲存到擷取的群組裡,然後用m.groups[1].value得到這個擷取的群組所匹配到的內容
m.groups[1].value是一種對捕獲的引用方式,還有另外一種引用方式m.result("$1"),效果是一樣的
普通擷取的群組是用1,2,3...這樣的自然數對擷取的群組進行引用的
而命名擷取的群組可以不用去數擷取的群組的序號,直接通過擷取的群組的命稱對它進行引用
c# code
string test = "<a href="http://anmo./" title="床上等你">csdn</a>";
match m = regex.match(test, @"<as*href=""(?<url>[^""]*)""[^>]*>", regexoptions.ignorecase);
if (m.success)
messagebox.show(m.groups["url"].value);
至於擷取的群組的分組命名及序號定序,在後面說明
2、非擷取的群組的作用
非擷取的群組的作用有兩個,第一個比較常用,第二個瞭解一下即可
(1)、節省系統資源,提高效率
在使用“ ¦”表示“或”的關係時,稍微複雜的情況,需要用()來限制“ ¦”的作用範圍,否則即表示“ ¦”的左右兩側整體為“或”的關係,這是題外話,這裡不詳細說明了,還有用{num}來運算式匹配次數時,有時前面也要用到()限制作用範圍
而使用()來限制作用範圍的同時,預設情況下會把匹配到的結果儲存到一個擷取的群組裡,而大多數時候,我們是不需要儲存這部分內容的,這就帶來一定的副作用,浪費了系統資源,降低了效率
非擷取的群組的一個作用就是用來消除這種副作用的,(?:exp)用來匹配exp所表示的規則,但不將匹配結果儲存到擷取的群組裡
比如匹配hh:mm:ss這樣的時間
c# code
messagebox.show(regex.ismatch("18:23:55", "^(?:[01][0-9]|2[0-3])(?::[0-5][0-9]){2}$").tostring());
(?:[01][0-9] ¦2[0-3])驗證小時部分是否符合規則,但不會將匹配結果儲存到擷取的群組裡
(?::[0-5][0-9]){2}驗證了分秒部分,但不會將匹配結果儲存到擷取的群組裡
(2)、在使用regex.split方法時,起到與regexoptions .explicitcapture參數相同的作用,這個用得不多,瞭解一下就行了
三、擷取的群組分組命名及序號排序
普通擷取的群組是按“(”從左至右出現的先後順序以自然數1,2,3...進行命名的
命名擷取的群組就是以(? <name> exp)中的name進行命名的
但是要注意一點,在運算式匹配成功的前提下,$0在任何情況下都表示整個運算式所匹配到的內容,m.groups[0].value表示整個運算式匹配到的內容,可以簡寫為m.value
另外就是命名擷取的群組除了可以用name對它進行引用外,還可以通過序號對它引用,它的命名規則為:先對普通擷取的群組從左至右進行序號命名,然後再從開頭,從左至右對命名擷取的群組進行序號命名,舉例如下
<as*href="(? <url> [^"]*)"s*title="([^"]*)"[^> ]*> (? <text> [ss]*?) </a>
2 url 1 3 text
c# code
string test = "<a href="http://anmo./" title="床上等你">csdn</a>";
match m = regex.match(test, @"<as*href=""(?<url>[^""]*)""s*title=""([^""]*)""[^>]*>(?<text>[ss]*?)</a>", regexoptions.ignorecase);
if (m.success)
{
richtextbox1.text += m.groups[0].value + "n"; //<a href="http://anmo./" title="床上等你">csdn</a>
richtextbox1.text += m.groups[1].value + "n"; //床上等你
richtextbox1.text += m.groups[2].value + "n"; //http://anmo.
richtextbox1.text += m.groups["url"].value + "n"; //http://anmo.
richtextbox1.text += m.groups[3].value + "n"; //csdn
richtextbox1.text += m.groups["text"].value + "n"; //csdn
}
四、組的另一種引用方式
除了上面 m.groups[1].value 和 m.result("$1") 這兩種對結果集進行處理時的引用方式外,還有在替換時的一種引用方式,舉例如下
只保留網址和連結文字,去掉 <a...> 標籤中其它無用資訊
c# code
string test = "<a href="http://anmo./" title="床上等你">csdn</a>";
string result = regex.replace(test, @"<as*href=""([^""]*)""s*title=""([^""]*)""[^>]*>(?<text>[ss]*?)</a>", @"<a href=""$1"">${text}</a>", regexoptions.ignorecase);
messagebox.show(result);
普通擷取的群組就是用$number來引用,而命名捕獲是用${name}來引用
預搜尋
(?=exp)
(?!exp)
(? <=exp)
(? <!exp)
下面的說明很容易讓人頭暈,不看也罷,我將以另一種方式對它們的作用和用法進行說明
(?=exp) 匹配exp前面的位置
(? <=exp) 匹配exp後面的位置
(?!exp) 匹配後面跟的不是exp的位置
(? <!exp) 匹配前面不是exp的位置
有的資料上翻譯為零寬度斷言,我習慣於預搜尋這種叫法,前兩個為正向預搜尋,後兩個為反向預搜尋,當然還有其它翻譯,其實都是一個意思,知道就行,不必在意
這四種運算式,它們與非捕獲的相同之處在於,並不將匹配到的結果儲存到擷取的群組,不同之處在於,非擷取的群組匹配到的內容,雖然不儲存到擷取的群組,但卻是在結果$0實實在在存在的,而以上四種運算式所匹配到的內容,一般來說,是不存在$0內的,所以說它們匹配的結果是零寬度的
更好的理解方式,是把它們作為附加條件,而不是Regex的組成部分
為了更好的說明,先說一下“縫隙”的概念,“縫隙”是零寬度的,它只是字串中的一個位置,而不是實際的字元,如字串“ab”,在“a”前面,“a”和“b”中間,還有“b”後面,分別有一個“縫隙”,也就是整個字串有三個“縫隙”
(?=exp) 在所在“縫隙”的後面附加一個條件,也就是“縫隙”後面必須能夠匹配exp的內容
(?!exp) 在所在“縫隙”的後面附加一個條件,也就是“縫隙”後面必須不能夠匹配exp的內容
(? <=exp) 在所在“縫隙”的前面附加一個條件,也就是“縫隙”前面必須能夠匹配exp的內容
(? <!exp) 在所在“縫隙”的前面附加一個條件,也就是“縫隙”前面必須不能夠匹配exp的內容
舉例說明如下:
<[^> ]*> 運算式任意html標籤
附加一個條件
<(?!img)[^> ]*>
這個就表示除 <img...> 標籤外的所有標籤,看下實際例子
c# code
string test = "<p><a href="http://anmo./" title="床上等你"><img src="yun_qi_img/logo.jpg/%22%3ecsdn%3c/a%3e%3c/p>";
matchcollection mc = regex.matches(test, @"<(?!img)[^>]*>", regexoptions .ignorecase);
foreach(match m in mc)
{
richtextbox1.text += m.value + "n";
}
輸出結果為:
<p>
<a href="http://www.111cn.net/" >
</a>
</p>
這時再看一下 <(?!img)[^> ]*> 這個Regex
(?!img)所在的“縫隙”是“ <”和它後面的第一個字元之間的“縫隙”,它表示的意思就是,在這個“縫隙”的後面,不能是img,整個運算式的意思也就是不匹配 <img...> 標籤
同理, <(?=img)[^> ]*> 表示只匹配 <img...> 標籤