C#正则表达式编程(三):Match类和Group类用法
生活随笔
收集整理的這篇文章主要介紹了
C#正则表达式编程(三):Match类和Group类用法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前面兩篇講述了正則表達式的基礎和一些簡單的例子,這篇將稍微深入一點探討一下正則表達式分組,在.NET中正則表達式分組是用Math類來代表的。
首先先看一段代碼:
/// <summary>
///?顯示Match內多個Group的例子
/// </summary>
public?void?ShowStructure()
{
????????//要匹配的字符串
????????string?text =?"1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
????????//正則表達式
????????string?pattern =?@"((\d+)([a-z]))\s+";
????????//使用RegexOptions.IgnoreCase枚舉值表示不區分大小寫
????????Regex r =?new?Regex(pattern, RegexOptions.IgnoreCase);
????????//使用正則表達式匹配字符串,僅返回一次匹配結果
????????Match m = r.Match(text);
????????while?(m.Success)
????????{
????????????????//顯示匹配開始處的索引值和匹配到的值
????????????????System.Console.WriteLine("Match=["?+ m +?"]");
????????????????CaptureCollection cc = m.Captures;
????????????????foreach?(Capture c?in?cc)
????????????????{
????????????????????????Console.WriteLine("\tCapture=["?+ c +?"]");
????????????????}
????????????????for?(int?i = 0; i < m.Groups.Count; i++)
????????????????{
????????????????????????Group group = m.Groups[i];
????????????????????????System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
????????????????????????for?(int?j = 0; j < group.Captures.Count; j++)
????????????????????????{
????????????????????????????????Capture capture = group.Captures[j];
????????????????????????????????Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
????????????????????????}
????????????????}
????????????????//進行下一次匹配.
????????????????m = m.NextMatch();
????????}
}
這段代碼的執行效果如下:
Match=[1A ]
?? ?Capture=[1A ]
?? ??? ?Groups[0]=[1A ]
?? ??? ??? ?Captures[0]=[1A ]
?? ??? ?Groups[1]=[1A]
?? ??? ??? ?Captures[0]=[1A]
?? ??? ?Groups[2]=[1]
?? ??? ??? ?Captures[0]=[1]
?? ??? ?Groups[3]=[A]
?? ??? ??? ?Captures[0]=[A]
Match=[2B ]
?? ?Capture=[2B ]
?? ??? ?Groups[0]=[2B ]
?? ??? ??? ?Captures[0]=[2B ]
?? ??? ?Groups[1]=[2B]
?? ??? ??? ?Captures[0]=[2B]
?? ??? ?Groups[2]=[2]
?? ??? ??? ?Captures[0]=[2]
?? ??? ?Groups[3]=[B]
?? ??? ??? ?Captures[0]=[B]
..................此去省略一些結果
Match=[16N ]
?? ?Capture=[16N ]
?? ??? ?Groups[0]=[16N ]
?? ??? ??? ?Captures[0]=[16N ]
?? ??? ?Groups[1]=[16N]
?? ??? ??? ?Captures[0]=[16N]
?? ??? ?Groups[2]=[16]
?? ??? ??? ?Captures[0]=[16]
?? ??? ?Groups[3]=[N]
?? ??? ??? ?Captures[0]=[N]
通過對上面的代碼結合代碼的分析,我們得出下面的結論,在((\d+)([a-z]))\s+這個正則表達式里總共包含了四個Group,即分組,按照默認的從左到右的匹配方式,其中Groups[0]代表了整個分組,其它的則是子分組,用示意圖表示如下:
?
在上面的代碼中是采用了Regex類的Match()方法,調用這種方法返回的是一個Match,要處理分析全部的字符串,還需要在while循環的中通過Match類的NextMatch()方法返回下一個可能成功的匹配(可通過Match類的Success屬性來判斷是否成功匹配)。上面的代碼還可以寫成如下形式:
/// <summary>
///?使用Regex類的Matches方法所有所有的匹配
/// </summary>
public?void?Matches()
{
????????//要匹配的字符串
????????string?text =?"1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
????????//正則表達式
????????string?pattern =?@"((\d+)([a-z]))\s+";
????????//使用RegexOptions.IgnoreCase枚舉值表示不區分大小寫
????????Regex r =?new?Regex(pattern, RegexOptions.IgnoreCase);
????????//使用正則表達式匹配字符串,返回所有的匹配結果
????????MatchCollection matchCollection = r.Matches(text);
????????foreach?(Match m?in?matchCollection)
????????{
????????????????//顯示匹配開始處的索引值和匹配到的值
????????????????System.Console.WriteLine("Match=["?+ m +?"]");
????????????????CaptureCollection cc = m.Captures;
????????????????foreach?(Capture c?in?cc)
????????????????{
????????????????????????Console.WriteLine("\tCapture=["?+ c +?"]");
????????????????}
????????????????for?(int?i = 0; i < m.Groups.Count; i++)
????????????????{
????????????????????????Group group = m.Groups[i];
????????????????????????System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
????????????????????????for?(int?j = 0; j < group.Captures.Count; j++)
????????????????????????{
????????????????????????????????Capture capture = group.Captures[j];
????????????????????????????????Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
????????????????????????}
????????????????}
????????}
}
上面的這段代碼和采用While循環遍歷所有匹配的結果是一樣的,在實際情況中有可能出現不需要全部匹配而是從某一個位置開始匹配的情況,比如從第32個字符處開始匹配,這種要求可以通過Match()或者Matches()方法的重載方法來實現,僅需要將剛才的實例代碼中的MatchCollection matchCollection = r.Matches(text);改為MatchCollection matchCollection = r.Matches(text,48);就可以了。
輸出結果如下:
Match=[5M ]
??????? Capture=[5M ]
??????????????? Groups[0]=[5M ]
??????????????????????? Captures[0]=[5M ]
??????????????? Groups[1]=[5M]
??????????????????????? Captures[0]=[5M]
??????????????? Groups[2]=[5]
??????????????????????? Captures[0]=[5]
??????????????? Groups[3]=[M]
??????????????????????? Captures[0]=[M]
Match=[16N ]
??????? Capture=[16N ]
??????????????? Groups[0]=[16N ]
??????????????????????? Captures[0]=[16N ]
??????????????? Groups[1]=[16N]
??????????????????????? Captures[0]=[16N]
??????????????? Groups[2]=[16]
??????????????????????? Captures[0]=[16]
??????????????? Groups[3]=[N]
??????????????????????? Captures[0]=[N]
注意上面的MatchCollection matchCollection = r.Matches(text,48)表示從text字符串的位置48處開始匹配,要注意位置0位于整個字符串的之前,位置1位于字符串中第一個字符之后第二個字符之前,示意圖如下(注意是字符串“1A”與“2B”之間有空格):
?
在text的位置48處正好是15M中的5處,因此返回的第一個Match是5M而不是15M。這里還繼續拿出第一篇中的圖來,如下:
?
從上圖可以看出Capture、Group及Match類之間存在繼承關系,處在繼承關系頂端的Capture類中就定義了Index、Length和Value屬性,其中Index表示原始字符串中發現捕獲子字符串的第一個字符的出現位置,Length屬性表示子字符串的長度,而Value屬性表示從原始字符串中捕獲的子字符串,利用這些屬性可以實現一些比較復雜的應用。例如在現在還有很多論壇仍沒有使用所見即所得的在線編輯器,而是使用了一種UBB編碼的編輯器,使用所見即所得的編輯器存在著一定的安全風險,比如可以在源代碼中嵌入js代碼或者其它惡意代碼,這樣瀏覽者訪問時就會帶來安全問題,而使用UBB代碼就不會代碼這個問題,因為UBB代碼包含了有限的、但不影響常規使用的標記并且支持UBB代碼的編輯器不允許直接在字符串中出現HTML代碼,也而就避免惡意腳本攻擊的問題。在支持UBB代碼的編輯器中輸入的文本在存入數據庫中保存的形式是UBB編碼,顯示的時候需要將UBB編碼轉換成HTML代碼,例如下面的一段代碼就是UBB編碼:
[url]http://zhoufoxcn.blog.51cto.com[/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]
下面通過例子演示如何將上面的UBB編碼轉換成HTML代碼:
/// <summary>
///?下面的代碼實現將文本中的UBB超級鏈接代碼替換為HTML超級鏈接代碼
/// </summary>
public?void?UBBDemo()
{
????????string?text =?"[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]";
????????Console.WriteLine("原始UBB代碼:"?+ text);
????????Regex regex =?new?Regex(@"(\[url=([ \S\t]*?)\])([^[]*)(\[\/url\])", RegexOptions.IgnoreCase);
????????MatchCollection matchCollection = regex.Matches(text);
????????foreach?(Match match?in?matchCollection)
????????{
????????????????string?linkText =?string.Empty;
????????????????//如果包含了鏈接文字,如第二個UBB代碼中存在鏈接名稱,則直接使用鏈接名稱
????????????????if?(!string.IsNullOrEmpty(match.Groups[3].Value))
????????????????{
????????????????????????linkText = match.Groups[3].Value;
????????????????}
????????????????else//否則使用鏈接作為鏈接名稱
????????????????{
????????????????????????linkText = match.Groups[2].Value;
????????????????}
????????????????text = text.Replace(match.Groups[0].Value,?"<a href=\""?+ match.Groups[2].Value +?"\" target=\"_blank\">"+ linkText +?"</a>");
????????}
????????Console.WriteLine("替換后的代碼:"+text);
}
程序執行結果如下:
原始UBB代碼:[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]
替換后的代碼:<a href="http://zhoufoxcn.blog.51cto.com" target="_blank">http://zhoufoxcn.blog.51cto.com</a><a href="http://blog.csdn.net/zhoufoxcn"target="_blank">周公的專欄</a>
首先先看一段代碼:
/// <summary>
///?顯示Match內多個Group的例子
/// </summary>
public?void?ShowStructure()
{
????????//要匹配的字符串
????????string?text =?"1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
????????//正則表達式
????????string?pattern =?@"((\d+)([a-z]))\s+";
????????//使用RegexOptions.IgnoreCase枚舉值表示不區分大小寫
????????Regex r =?new?Regex(pattern, RegexOptions.IgnoreCase);
????????//使用正則表達式匹配字符串,僅返回一次匹配結果
????????Match m = r.Match(text);
????????while?(m.Success)
????????{
????????????????//顯示匹配開始處的索引值和匹配到的值
????????????????System.Console.WriteLine("Match=["?+ m +?"]");
????????????????CaptureCollection cc = m.Captures;
????????????????foreach?(Capture c?in?cc)
????????????????{
????????????????????????Console.WriteLine("\tCapture=["?+ c +?"]");
????????????????}
????????????????for?(int?i = 0; i < m.Groups.Count; i++)
????????????????{
????????????????????????Group group = m.Groups[i];
????????????????????????System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
????????????????????????for?(int?j = 0; j < group.Captures.Count; j++)
????????????????????????{
????????????????????????????????Capture capture = group.Captures[j];
????????????????????????????????Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
????????????????????????}
????????????????}
????????????????//進行下一次匹配.
????????????????m = m.NextMatch();
????????}
}
這段代碼的執行效果如下:
Match=[1A ]
?? ?Capture=[1A ]
?? ??? ?Groups[0]=[1A ]
?? ??? ??? ?Captures[0]=[1A ]
?? ??? ?Groups[1]=[1A]
?? ??? ??? ?Captures[0]=[1A]
?? ??? ?Groups[2]=[1]
?? ??? ??? ?Captures[0]=[1]
?? ??? ?Groups[3]=[A]
?? ??? ??? ?Captures[0]=[A]
Match=[2B ]
?? ?Capture=[2B ]
?? ??? ?Groups[0]=[2B ]
?? ??? ??? ?Captures[0]=[2B ]
?? ??? ?Groups[1]=[2B]
?? ??? ??? ?Captures[0]=[2B]
?? ??? ?Groups[2]=[2]
?? ??? ??? ?Captures[0]=[2]
?? ??? ?Groups[3]=[B]
?? ??? ??? ?Captures[0]=[B]
..................此去省略一些結果
Match=[16N ]
?? ?Capture=[16N ]
?? ??? ?Groups[0]=[16N ]
?? ??? ??? ?Captures[0]=[16N ]
?? ??? ?Groups[1]=[16N]
?? ??? ??? ?Captures[0]=[16N]
?? ??? ?Groups[2]=[16]
?? ??? ??? ?Captures[0]=[16]
?? ??? ?Groups[3]=[N]
?? ??? ??? ?Captures[0]=[N]
通過對上面的代碼結合代碼的分析,我們得出下面的結論,在((\d+)([a-z]))\s+這個正則表達式里總共包含了四個Group,即分組,按照默認的從左到右的匹配方式,其中Groups[0]代表了整個分組,其它的則是子分組,用示意圖表示如下:
?
在上面的代碼中是采用了Regex類的Match()方法,調用這種方法返回的是一個Match,要處理分析全部的字符串,還需要在while循環的中通過Match類的NextMatch()方法返回下一個可能成功的匹配(可通過Match類的Success屬性來判斷是否成功匹配)。上面的代碼還可以寫成如下形式:
/// <summary>
///?使用Regex類的Matches方法所有所有的匹配
/// </summary>
public?void?Matches()
{
????????//要匹配的字符串
????????string?text =?"1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
????????//正則表達式
????????string?pattern =?@"((\d+)([a-z]))\s+";
????????//使用RegexOptions.IgnoreCase枚舉值表示不區分大小寫
????????Regex r =?new?Regex(pattern, RegexOptions.IgnoreCase);
????????//使用正則表達式匹配字符串,返回所有的匹配結果
????????MatchCollection matchCollection = r.Matches(text);
????????foreach?(Match m?in?matchCollection)
????????{
????????????????//顯示匹配開始處的索引值和匹配到的值
????????????????System.Console.WriteLine("Match=["?+ m +?"]");
????????????????CaptureCollection cc = m.Captures;
????????????????foreach?(Capture c?in?cc)
????????????????{
????????????????????????Console.WriteLine("\tCapture=["?+ c +?"]");
????????????????}
????????????????for?(int?i = 0; i < m.Groups.Count; i++)
????????????????{
????????????????????????Group group = m.Groups[i];
????????????????????????System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
????????????????????????for?(int?j = 0; j < group.Captures.Count; j++)
????????????????????????{
????????????????????????????????Capture capture = group.Captures[j];
????????????????????????????????Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
????????????????????????}
????????????????}
????????}
}
上面的這段代碼和采用While循環遍歷所有匹配的結果是一樣的,在實際情況中有可能出現不需要全部匹配而是從某一個位置開始匹配的情況,比如從第32個字符處開始匹配,這種要求可以通過Match()或者Matches()方法的重載方法來實現,僅需要將剛才的實例代碼中的MatchCollection matchCollection = r.Matches(text);改為MatchCollection matchCollection = r.Matches(text,48);就可以了。
輸出結果如下:
Match=[5M ]
??????? Capture=[5M ]
??????????????? Groups[0]=[5M ]
??????????????????????? Captures[0]=[5M ]
??????????????? Groups[1]=[5M]
??????????????????????? Captures[0]=[5M]
??????????????? Groups[2]=[5]
??????????????????????? Captures[0]=[5]
??????????????? Groups[3]=[M]
??????????????????????? Captures[0]=[M]
Match=[16N ]
??????? Capture=[16N ]
??????????????? Groups[0]=[16N ]
??????????????????????? Captures[0]=[16N ]
??????????????? Groups[1]=[16N]
??????????????????????? Captures[0]=[16N]
??????????????? Groups[2]=[16]
??????????????????????? Captures[0]=[16]
??????????????? Groups[3]=[N]
??????????????????????? Captures[0]=[N]
注意上面的MatchCollection matchCollection = r.Matches(text,48)表示從text字符串的位置48處開始匹配,要注意位置0位于整個字符串的之前,位置1位于字符串中第一個字符之后第二個字符之前,示意圖如下(注意是字符串“1A”與“2B”之間有空格):
?
在text的位置48處正好是15M中的5處,因此返回的第一個Match是5M而不是15M。這里還繼續拿出第一篇中的圖來,如下:
?
從上圖可以看出Capture、Group及Match類之間存在繼承關系,處在繼承關系頂端的Capture類中就定義了Index、Length和Value屬性,其中Index表示原始字符串中發現捕獲子字符串的第一個字符的出現位置,Length屬性表示子字符串的長度,而Value屬性表示從原始字符串中捕獲的子字符串,利用這些屬性可以實現一些比較復雜的應用。例如在現在還有很多論壇仍沒有使用所見即所得的在線編輯器,而是使用了一種UBB編碼的編輯器,使用所見即所得的編輯器存在著一定的安全風險,比如可以在源代碼中嵌入js代碼或者其它惡意代碼,這樣瀏覽者訪問時就會帶來安全問題,而使用UBB代碼就不會代碼這個問題,因為UBB代碼包含了有限的、但不影響常規使用的標記并且支持UBB代碼的編輯器不允許直接在字符串中出現HTML代碼,也而就避免惡意腳本攻擊的問題。在支持UBB代碼的編輯器中輸入的文本在存入數據庫中保存的形式是UBB編碼,顯示的時候需要將UBB編碼轉換成HTML代碼,例如下面的一段代碼就是UBB編碼:
[url]http://zhoufoxcn.blog.51cto.com[/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]
下面通過例子演示如何將上面的UBB編碼轉換成HTML代碼:
/// <summary>
///?下面的代碼實現將文本中的UBB超級鏈接代碼替換為HTML超級鏈接代碼
/// </summary>
public?void?UBBDemo()
{
????????string?text =?"[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]";
????????Console.WriteLine("原始UBB代碼:"?+ text);
????????Regex regex =?new?Regex(@"(\[url=([ \S\t]*?)\])([^[]*)(\[\/url\])", RegexOptions.IgnoreCase);
????????MatchCollection matchCollection = regex.Matches(text);
????????foreach?(Match match?in?matchCollection)
????????{
????????????????string?linkText =?string.Empty;
????????????????//如果包含了鏈接文字,如第二個UBB代碼中存在鏈接名稱,則直接使用鏈接名稱
????????????????if?(!string.IsNullOrEmpty(match.Groups[3].Value))
????????????????{
????????????????????????linkText = match.Groups[3].Value;
????????????????}
????????????????else//否則使用鏈接作為鏈接名稱
????????????????{
????????????????????????linkText = match.Groups[2].Value;
????????????????}
????????????????text = text.Replace(match.Groups[0].Value,?"<a href=\""?+ match.Groups[2].Value +?"\" target=\"_blank\">"+ linkText +?"</a>");
????????}
????????Console.WriteLine("替換后的代碼:"+text);
}
程序執行結果如下:
原始UBB代碼:[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的專欄[/url]
替換后的代碼:<a href="http://zhoufoxcn.blog.51cto.com" target="_blank">http://zhoufoxcn.blog.51cto.com</a><a href="http://blog.csdn.net/zhoufoxcn"target="_blank">周公的專欄</a>
上面的這個例子就稍微復雜點,對于初學正則表達式的朋友來說,可能有點難于理解,不過沒有關系,后面我會講講正則表達式。在實際情況下,可能通過match.Groups[0].Value這種方式不太方便,就想在訪問DataTable時寫string name=dataTable.Rows[i][j]這種方式一樣,一旦再次調整,這種通過索引的方式極容易出錯,實際上我們也可以采用名稱而不是索引的放來來訪問Group分組,這個也會在以后的篇幅中去講。
本文轉自周金橋51CTO博客,原文鏈接:?http://blog.51cto.com/zhoufoxcn/281956,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的C#正则表达式编程(三):Match类和Group类用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实战操作主机角色转移,Active Di
- 下一篇: CCNP-1 EIGRP基本配置(BSC