正則表達式,主要是用符號描述了一類特定的文本(模式)。而正則表達式引擎則負責在給定的字符串中,查找到這一特定的文本。
本文主要是列出常用的正則表達式符號,加以歸類說明。本文僅僅是快速理解了正則表達式相關元字符,作一個備忘,供以後理解更復雜表達式的參考,以後關於正則表達式的相關內容會持續更新本文。示例語言用C#
概述
普通字符
字符集合
速記的字符集合
指定重復次數的字符
匹配位置字符
分支替換字符
匹配特殊字符
組,反向引用,非捕獲組
貪婪與非貪婪
回溯與非回溯
正向預搜索、反向預搜索
最後
最簡單的一種文本描述,就是直接給出要匹配內容。 如要在”Generic specialization, the decorator pattern, chains of responsibilities, and extensible software.” 找到pattern,那麼正則式就直接是”heels”即可
string input = "Generic specialization, the decorator pattern, chains of responsibilities, and extensible software."; Regex reg = new Regex("pattern", RegexOptions.IgnoreCase); Console.WriteLine(reg.Matches(input).Count); //output 1 View Code
將字符放在中括號中,即為字符集合。通過字符集合告訴正則式引擎從字符集合中的字符,僅匹配出一個字符。
比如單詞灰色gray(英)和grey(美),在一段文本中匹配出gray或grey,那麼通過正則式gr[ae]y 就可以了;又比如要在一段文本中找到me和my,正則式是m[ey]
我們還可以在字符集合中使用連字號 – 來表示一個范圍,比如 [0-9] 表示匹配一個0到9數字;[a-zA-Z] 表示匹配英文字母;[0-9 a-zA-Z]表示匹配一個0到9的數字或英文字母
string input = "The color of shirt is gray and color of shoes is grey too."; Regex reg = new Regex("gr[ae]y", RegexOptions.IgnoreCase); Console.WriteLine(reg.Matches(input).Count); //output 2 var matchs = reg.Matches(input); foreach (Match match in matchs) { Console.WriteLine(match.Value);//output gray grey } View Code
我們常常要匹配一個數字,一個字母,一個空白符,雖然可以用普通的字符類來表示,但不夠方便,所以正則式提示了一些常用的字符集合的速記符
指定重復匹配前面的字符多少次:匹配重復的次數,不匹配內容。比如說,要在一系列電話號碼中找到以158開始的11位手機號,如果我們沒有學過下面的內容,正則表達式為158\d\d\d\d\d\d\d\d;但如果我們學習了下面的知識,則正則表達式為158\d{8}
現在我們已經學會了使用字符集合,字符集合的速記符來匹配大部分的文本了。但是如果我們遇到以下的情況,怎麼辦?
要求匹配文本的第一個單詞為google
要求匹配文本以bye結束
要求匹配文本每一行的第一個單詞為數字
要求匹配一個單詞以hel開頭
上面的這種匹配一個位置,但不匹配任何內容的需求很正常。在正則表達式中也提供了一些特殊的字符來匹配位置(不匹配內容)。如用^匹配文本的開始位置, 用$匹配文本的結束位置,\b匹配一個單詞的邊界
在字符集合中,我們可以在用中括號來指定匹配中括號中的任一字符,即模式中可以列出多種字符情景,被匹配的文本只要有符合其中的任一情景就可以被匹配出來。 那有沒有這樣的一種機制,同一個正則式中有多個模式,只有滿足其中的任一模式就可以被匹配出來。再配合分組,就可以把一個復雜的正則式分成多個相對簡單子的正則式來做。類似於邏輯符號OR的意思吧。
到現在,我們已經知道了字符集合,一些速記的字符集合,匹配位置的字符,指定匹配次數的字符,分支匹配。我們用的這些符號,在正則表達式中代表了各種特定的意義。那當我們要匹配這些字符本身,我們應該怎麼辦?在特殊字符前加上\, 以下是一些常用特殊字符的轉義字符的列表
組,可以用圓括號,將正則表達式的部分括起來並獨立使用,在圓括號之間的正則式叫做一個組。可以將匹配次數的字符和分支匹配字符應用到組。
1 示例: public void Set, public void SetValue
正則式Set(Value)? , 其中(Value)是一個組,匹配次數的字符?將應用於整個組(Value),可以匹配到Set或SetValue
2 示例:Out of sight, out of mind
正則式: “(out of) sight, \1 mind”
正則表達式引擎會將 “()”中匹配到的內容存儲起來,作為一個“組”,並且可以通過索引的方式進行引用。表達式中的“\1”,用於反向引用表達式中出現的第一個組。 同時在c#中,也可以通過組來訪問捕獲到的組的內容。注意,Groups[0]是整個匹配的字符串,組的內容從索引1開始
3 可根據組名進行索引。使用以下格式為標識一個組的名稱(?<groupname>…)
正則式: “(?<Group1>out of) sight, \1 mind”
string input2 = "out of sight, out of mind"; Regex reg2 = new Regex(@"(?<Group1>out of) sight, \1 mind"); if (reg2.IsMatch(input2)) { Console.WriteLine(reg2.Match(input2).Value);//output out of sight, out of mind } Console.WriteLine(reg2.Match(input2).Groups["Group1"].Value); // output out of View Code
4在表達式外引用,對於索外用$索引,或組名用${組名}
示例:Out of of sight, out of mind
正則式 “(?<Group1>[a-z]+) \1”
string input3 = "out of sight, out out of mind mind"; Regex reg3 = new Regex(@"(?<Group1>[a-z]+) \1");//匹配重復的單詞 if(reg3.IsMatch(input3)) { Console.WriteLine(reg3.Replace(input3, "$1"));//output out of sight, out of mind Console.WriteLine(reg3.Replace(input3, "${Group1}"));//output out of sight, out of mind } View Code
5非捕獲組,在組前加上?: 因為有的組表達的僅僅是一個選擇替換,當我們不想用浪費存儲時,以用不捕獲該組
"(?:out of) sight"
string input4 = "out of sight, out of mind"; Regex reg4 = new Regex(@"(?:out of) sight");//使用了非捕獲?:後,在表達式內就不能使用\1去引用了 if (reg4.IsMatch(input4)) { Console.WriteLine(reg4.Match(input4).Groups[1].Value); // output 空 } View Code
正則表達式的引擎默認是貪婪,只要模式允許,它將匹配盡可能多的字符。通過在“重復描述字符(*,+等)”後面添加“?”,可以將匹配模式改成非貪婪。貪婪與非貪婪與指定重復次數的字符的內容密切相關。
示例 out of sight, out of mind
貪婪正則式 : .* of 輸出out of sight, out of
非貪婪正則式 : .*? of 輸出 out of
另外一個示例
輸入:The title of cnblog is <h1>code changes the world</h1>
目標:匹配HTML標記
正則式1:<.+>
正則式1的輸出: <h1>code changes the world</h1>
正則式2:<.+?>
正則式2的輸出: <h1> </h1>
string input1 = "out of sight, out of mind"; Regex reg1 = new Regex(@".* of");//默認貪婪模式,盡可能的匹配更多的文本。在遇到第一個of時,正則引擎並沒有停止下來,繼續執行以期望後面還有一個of,這樣就可以匹配到更多的文本。如果後面沒有匹配到新的of,剛執行回溯 if (reg1.IsMatch(input1)) { Console.WriteLine(reg1.Match(input1).Value);//output out of sight, out of } string input2 = "out of sight, out of mind"; Regex reg2 = new Regex(@".*? of");//在指定重復次數的字符後面加上?,正則式則為非貪婪模式。一但遇到第一個符合條件的文本,就匹配結束 if (reg2.IsMatch(input2)) { Console.WriteLine(reg2.Match(input2).Value);//output out of } string input3 = "The title of cnblog is <h1>code changes the world</h1>"; Regex reg3 = new Regex(@"<.+>");//貪婪模式:匹配HTML標記 var matchs3 = reg3.Matches(input3); foreach (Match match in matchs3) { Console.WriteLine(match.Value);//output <h1>code changes the world</h1> } string input4 = "The title of cnblog is <h1>code changes the world</h1>"; Regex reg4 = new Regex(@"<.+?>");//非貪婪模式:匹配HTML標記 var matchs4 = reg4.Matches(input4); foreach (Match match in matchs4) { Console.WriteLine(match.Value);//output <h1> </h1> } View Code使用“(?>…)”方式進行非回溯聲明。由於正則表達式引擎的貪婪特性,導致它在某些情況下,將進行回溯以獲得匹配,請看下面的示例:
示例:Live for nothing, die for something
正則式(默認非回溯): “.*thing,” 輸出Live for nothing, 。“.*”由於其貪婪特性,將一直匹配到字符串的最後,隨後匹配“thing”,但在匹配“,”時失敗,此時引擎將回溯,並在“thing,”處匹配成功
正則式(回溯):”(?>.*)thing,” 匹配不到任何東西。由於強制非回溯,所以整個表達式匹配失敗
string input1 = "Live for nothing, die for something"; Regex reg1 = new Regex(@"(.*)thing,"); var matchs1 = reg1.Matches(input1); foreach (Match match in matchs1) { Console.WriteLine(match.Value);//output } Regex reg2= new Regex(@"(?>.*)thing,"); var matchs2 = reg2.Matches(input1); foreach (Match match in matchs2) { Console.WriteLine(match.Value);//output } View Code
匹配特定的模式,並聲明前面或後面的內容。意思跟匹配位置差不多
參考地址:
正則表達式30分鐘入門教程
Regular Expressions Tutorial
NET Framework Regular Expressions
.NET進階系列之一:C#正則表達式整理備忘