標籤:blog http 使用 strong cti for
正則的力量無法小覷,短短的幾個字元,往往勝過幾十行的代碼,大大可以簡化我們冗餘的代碼。
以前在js裡用正則比較多,今天來熟悉下C#中正則的使用方法,權當筆記了!
如果把正則當做一門語言的話,那麼正則的學習也和其他語言一樣,從曆史淵源到基本文法,從進階特性到效能最佳化,正則一樣不少。
曆史:
1 |
Regex的“祖先”可以一直上溯至對人類神經系統如何工作的早期研究。Warren McCulloch 和 Walter Pitts 這兩位神經生理學家研究出一種數學方式來描述這些神經網路。 1956 年, 一位叫 Stephen Kleene 的數學家在 McCulloch 和 Pitts 早期工作的基礎上,發表了一篇標題為“神經網事件的標記法”的論文,引入了Regex的概念。Regex就是用來描述他稱為“正則集的代數”的運算式,因此採用“Regex”這個術語。 隨後,發現可以將這一工作應用於使用 Ken Thompson 的計算搜尋演算法的一些早期研究,Ken Thompson 是 Unix 的主要發明人。Regex的第一個實用應用程式就是 Unix 中的 qed 編輯器。 如他們所說,剩下的就是眾所周知的曆史了。從那時起直至現在Regex都是基於文本的編輯器和搜尋工具中的一個重要部分。 |
基本文法字元:
\d (代表0-9的數字)
\D (代表除數字以外的其他字元)
\w (代表所有的單詞字元-數字、字母、底線)
\W (代表所有除單詞字元外的字元)
\s (代表空白字元)
\S (代表除了空白字元以外的字元)
. (除了分行符號外的任一字元)
[,,,] (匹配方括弧內列出的所有字元)
[^,,,] (匹配方括弧內列出的字元外的所有字元)
\b (匹配單詞邊界)
\B (匹配非單詞邊界)
^ (匹配字元開頭位置)
$ (匹配字元結尾位置)
{n} (匹配n個合格字元)
{n,m} (匹配n到m個合格字元)
{n,} (匹配大於等於n個合格字元)
? (匹配1次或0次合格字元)
+ (匹配一次或多次合格字元)
* (匹配0次或多次合格字元)
(a|b) (匹配符合a條件或者b條件的字元)
下面練習一些基本的例子來熟悉上面的基本文法
1.匹配3個數字,例如134
\d{3}
2.匹配一個單詞以字母開頭字母結尾中間是一個或多個數字,例如a123b
^[a-zA-Z]\d+[a-zA-Z]$
3.匹配固定電話 例如 021-81234563 或者 0512-81755456
^\d{3,4}-\d{8}
4.匹配正整數
[1-9][0-9]*
5.匹配兩位小數
(([0-9][1-9]*)|([1-9][0-9]*))+\.\d{2}
6.匹配郵遞區號
^\d{6}$
7.匹配手機號碼
^[1][3-9]\d{9}$
8.匹配社會安全號碼碼
^\d{18}$)|^\d{15}$
9.匹配漢字
^[\u4e00-\u9fa5]{1,}$
10.匹配URL
^http(s)?([\w-]+\.)+(\w-)+(/[\w-./?%&=]*)?$
上述是基本的使用文法,讓我們來看看C#中是如何使用它們的
System.Text.RegularExpressions.Regex 這個事C#正則的使用類
他提供了如下方法來使用正則
1.IsMatch 是否匹配-範例程式碼:
1 //驗證手機號碼2 public bool IsMobile(string mobile) {3 return System.Text.RegularExpressions.Regex.IsMatch(mobile, @"^[1][3-9]\d{9}$");4 }
2.Split 根據條件切割字串
範例程式碼
//根據數字拆分字串 public String[] SplitStr(String str) { return System.Text.RegularExpressions.Regex.Split(str, @"[0-9]"); } protected void btn_split_Click(object sender, EventArgs e) { string[] Result = SplitStr(this.tb_pwd.Text); int Len = Result.Length; for (int i = 0; i < Len; i++) { if (Result[i] != "") { Response.Write("<script>alert(‘拆分為!" + Result[i] + "‘)</script>"); } } }
3.Replace
替換字串
1 //替換字串中的所有數字為指定字元2 public String ReplaceWord(string str1, string str2) {3 return System.Text.RegularExpressions.Regex.Replace(str1, @"\d", str2);4 }
4.Matches
擷取匹配集合
1 //驗證重複出現的詞(正則需要最佳化) 2 public String[] RepeatWords(string str) { 3 System.Text.RegularExpressions.MatchCollection matches = 4 System.Text.RegularExpressions.Regex.Matches(str, @"\b(?<word>\w+)\s+(\k<word>)\b", System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.IgnoreCase); 5 int AIndex = matches.Count; 6 if (AIndex != 0) { 7 String[] RepeatWord = new string[AIndex]; 8 int i=0; 9 foreach (System.Text.RegularExpressions.Match match in matches) {10 string word = match.Groups["word"].Value;11 RepeatWord[i] = word;12 i++;13 }14 return RepeatWord;15 }16 else {17 return null;18 }19 }
正則的進階特性
1.分組和非捕獲性分組
組是把符合括弧中組條件的字元儲存起來,通過索引的方法供下面的匹配的調用
例如 需要匹配 abc123abc
我們可以這樣^(abc)123\1$,這裡的()即是一個需要捕獲的組,他的條件是abc,這個時候在下一個位置,我們只要通過\1就可以重複利用上一次捕獲過的值來匹配,如果有兩個分組,那我們擷取第二個分組就用\2
那在C#中如何利用呢?
string x = "abc123abc";Regex r = new Regex(@"^(abc)123\1$");if (r.IsMatch(x)){Console.WriteLine("group1 value:" + r.Match(x).Groups[1].Value);//輸出:abc}
這裡為何是Groups[1]呢 因為在匹配的時候第一個匹配的是符合所有條件的字串,然後儲存合格組
我們也可以為組命名:
string x = "abc123abc";Regex r = new Regex(@"^(?<test>abc)123\1$");if (r.IsMatch(x)){Console.WriteLine("group1 value:" + r.Match(x).Groups["test"].Value);//輸出:abc}
這樣是不是就更加形象了呢
有的時候我們想匹配組但是不想儲存這個組匹配的內容,這個時候我們可以使用?:
1 string x = "abc123abc";2 Regex r = new Regex(@"^(?:abc)123\1$");3 if (r.IsMatch(x))4 {5 Console.WriteLine("group1 value:" + r.Match(x).Groups[1].Value);//輸出:null6 }
2.貪婪模式和非貪婪模式
一般情況下,正則都是貪婪模式,尤其是在+或者*修飾的條件下,正則都會去儘可能的匹配更多的內容,但是如果添加了?號,這個時候立馬就會變成非貪婪模式
1 string x = "Live for nothing,die for something"; 2 Regex r1 = new Regex(@".*thing"); 3 if (r1.IsMatch(x)) 4 { 5 Console.WriteLine("match:" + r1.Match(x).Value);//輸出:Live for nothing,die for something 6 } 7 Regex r2 = new Regex(@".*?thing"); 8 if (r2.IsMatch(x)) 9 {10 Console.WriteLine("match:" + r2.Match(x).Value);//輸出:Live for nothing11 }
3.回溯與非回溯
在預設情況下正則匹配貪婪模式下,當匹配的字元陷入死胡同的時候,會進行回溯直到下一個字元能夠接著匹配
比如 (.*)abc 來匹配123abc123abc 首先.*會進行貪婪匹配直到匹配到字元結尾的位置,接著匹配a,發現沒有字元可以匹配上,引擎就向後回溯,直到a匹配到最後abc中的a,然後緊接著匹配b,然後匹配c 所以結果是 123abc123abc
好,接著來說明下非回溯模式的執行過程,同樣首先.*像一隻餓狼般的匹配到字元的結尾位置,這個時候開始匹配a 發現已經無法匹配,此模式下,不進行回溯,於是匹配失敗,在有的業務下我們需要這樣的非回溯匹配 ,文法例:(?>.*)abc
4.正向預搜尋反向預搜尋
不好解釋,舉例說明
正向預搜尋
string x = "1024 used 2048 free";Regex r1 = new Regex(@"\d{4}(?= used)");if (r1.Matches(x).Count==1){Console.WriteLine("r1 match:" + r1.Match(x).Value);//輸出:1024}Regex r2 = new Regex(@"\d{4}(?! used)");if (r2.Matches(x).Count==1){Console.WriteLine("r2 match:" + r2.Match(x).Value); //輸出:2048}
r1表示匹配後面緊跟著used的四個數字 於是乎匹配了1024 r2 匹配後面不是緊跟著used的四個數字 於是乎 匹配2048
反向預搜尋
string x = "used:1024 free:2048";Regex r1 = new Regex(@"(?<=used:)\d{4}");if (r1.Matches(x).Count==1){Console.WriteLine("r1 match:" + r1.Match(x).Value);//輸出:1024}Regex r2 = new Regex(@"(?<!used:)\d{4}");if (r2.Matches(x).Count==1){Console.WriteLine("r2 match:" + r2.Match(x).Value);//輸出:2048}
r1匹配前面緊著著used:的四個數字 於是乎匹配1024 r2匹配前面不是緊跟著used:的四個數字 於是乎撇配2048
看著例子理解就很好理解了,另外正向和反向的組是不儲存的