日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C#利用正則表達(dá)式實(shí)現(xiàn)字符串搜索

 busfly 2007-02-10
摘要:本文給出了在C#下利用正則表達(dá)式實(shí)現(xiàn)字符串搜索功能的方法,通過(guò)對(duì).NET框架下的正則表達(dá)式的研究及實(shí)例分析,總結(jié)了正則表達(dá)式的元字符、規(guī)則、選項(xiàng)等。

  關(guān)鍵字:正則表達(dá)式、元字符、字符串、匹配

  1、正則表達(dá)式簡(jiǎn)介

  正則表達(dá)式提供了功能強(qiáng)大、靈活而又高效的方法來(lái)處理文本。正則表達(dá)式的全面模式匹配表示法可以快速地分析大量的文本以找到特定的字符模式;提取、編輯、替換或刪除文本子字符串;或?qū)⑻崛〉淖址砑拥郊弦陨蓤?bào)告。對(duì)于處理字符串(例如 HTML處理、日志文件分析和 HTTP 標(biāo)頭分析)的許多應(yīng)用程序而言,正則表達(dá)式是不可缺少的工具。

  .NET 框架正則表達(dá)式并入了其他正則表達(dá)式實(shí)現(xiàn)的最常見(jiàn)功能,被設(shè)計(jì)為與 Perl 5 正則表達(dá)式兼容,.NET 框架正則表達(dá)式還包括一些在其他實(shí)現(xiàn)中尚未提供的功能,.NET 框架正則表達(dá)式類(lèi)是基類(lèi)庫(kù)的一部分,并且可以和面向公共語(yǔ)言運(yùn)行庫(kù)的任何語(yǔ)言或工具一起使用。

  2、字符串搜索

  正則表達(dá)式語(yǔ)言由兩種基本字符類(lèi)型組成:原義(正常)文本字符和元字符。正是元字符組為正則表達(dá)式提供了處理能力。當(dāng)前,所有的文本編輯器都有一些搜索功能,通??梢源蜷_(kāi)一個(gè)對(duì)話(huà)框,在其中的一個(gè)文本框中鍵入要定位的字符串,如果還要同時(shí)進(jìn)行替換操作,可以鍵入一個(gè)替換字符串,比如在Windows操作系統(tǒng)中的記事本、Office系列中的文檔編輯器都有這種功能。這種搜索最簡(jiǎn)單的方式,這類(lèi)問(wèn)題很容易用String類(lèi)的String.Replace()方法來(lái)解決,但如果需要在文檔中識(shí)別某個(gè)重復(fù)的,該怎么辦?編寫(xiě)一個(gè)例程,從一個(gè)String類(lèi)中選擇重復(fù)的字是比較復(fù)雜的,此時(shí)使用語(yǔ)言就很適合。

  一般表達(dá)式語(yǔ)言是一種可以編寫(xiě)搜索表達(dá)式的語(yǔ)言。在該語(yǔ)言中,可以把文檔中要搜索的文本、轉(zhuǎn)義序列和特定含義的其他字符組合在一起,例如序列\(zhòng)b表示一個(gè)字的開(kāi)頭和結(jié)尾(子的邊界),如果要表示正在查找的以字符th開(kāi)頭的字,就可以編寫(xiě)一般表達(dá)式\bth(即序列字符界是-t-h)。如果要搜索所有以th結(jié)尾的字,就可以編寫(xiě)th\b(序列t-h-字邊界)。但是,一般表達(dá)式要比這復(fù)雜得多,例如,可以在搜索操作中找到存儲(chǔ)部分文本的工具性程序(facility)。
3、.NET 框架的正則表達(dá)式類(lèi)

  下面通過(guò)介紹 .NET 框架的正則表達(dá)式類(lèi),熟悉一下.NET框架下的正則表達(dá)式的使用方法。

  3.1 Regex 類(lèi)表示只讀正則表達(dá)式

  Regex 類(lèi)包含各種靜態(tài)方法,允許在不顯式實(shí)例化其他類(lèi)的對(duì)象的情況下使用其他正則表達(dá)式類(lèi)。以下代碼示例創(chuàng)建了 Regex 類(lèi)的實(shí)例并在初始化對(duì)象時(shí)定義一個(gè)簡(jiǎn)單的正則表達(dá)式。請(qǐng)注意,使用了附加的反斜杠作為轉(zhuǎn)義字符,它將 \s 匹配字符類(lèi)中的反斜杠指定為原義字符。

  

  Regex r; // 聲明一個(gè) Regex類(lèi)的變量

  r = new Regex("\\s2000"); // 定義表達(dá)式

  3.2 Match 類(lèi)表示正則表達(dá)式匹配操作的結(jié)果

  以下示例使用 Regex 類(lèi)的 Match 方法返回 Match 類(lèi)型的對(duì)象,以便找到輸入字符串中第一個(gè)匹配。此示例使用 Match 類(lèi)的 Match.Success 屬性來(lái)指示是否已找到匹配。

  

  Regex r = new Regex("abc"); // 定義一個(gè)Regex對(duì)象實(shí)例

  Match m = r.Match("123abc456"); // 在字符串中匹配

  if (m.Success)

  {

   Console.WriteLine("Found match at position " + m.Index); //輸入匹配字符的位置

  }

  3.3 MatchCollection 類(lèi)表示非重疊匹配的序列

  該集合為只讀的,并且沒(méi)有公共構(gòu)造函數(shù)。MatchCollection 的實(shí)例是由 Regex.Matches 屬性返回的。使用 Regex 類(lèi)的 Matches 方法,通過(guò)在輸入字符串中找到的所有匹配填充 MatchCollection。下面代碼示例演示了如何將集合復(fù)制到一個(gè)字符串?dāng)?shù)組(保留每一匹配)和一個(gè)整數(shù)數(shù)組(指示每一匹配的位置)中。

  

  MatchCollection mc;

  String[] results = new String[20];

  int[] matchposition = new int[20];

  Regex r = new Regex("abc"); //定義一個(gè)Regex對(duì)象實(shí)例

  mc = r.Matches("123abc4abcd");

  for (int i = 0; i < mc.Count; i++) //在輸入字符串中找到所有匹配

  {

   results[i] = mc[i].Value; //將匹配的字符串添在字符串?dāng)?shù)組中

   matchposition[i] = mc[i].Index; //記錄匹配字符的位置

  }

  3.4 GroupCollection 類(lèi)表示捕獲的組的集合

  該集合為只讀的,并且沒(méi)有公共構(gòu)造函數(shù)。GroupCollection 的實(shí)例在 Match.Groups 屬性返回的集合中返回。下面的控制臺(tái)應(yīng)用程序查找并輸出由正則表達(dá)式捕獲的組的數(shù)目。

  

  using System;

  using System.Text.RegularExpressions;

  public class RegexTest

  {

   public static void RunTest()

   {

    Regex r = new Regex("(a(b))c"); //定義組

    Match m = r.Match("abdabc");

    Console.WriteLine("Number of groups found = " + m.Groups.Count);

   }

   public static void Main()

   {

    RunTest();

   }

  }

  該示例產(chǎn)生下面的輸出:

  

  Number of groups found = 3

  3.5 CaptureCollection 類(lèi)表示捕獲的子字符串的序列

  由于限定符,捕獲組可以在單個(gè)匹配中捕獲多個(gè)字符串。Captures屬性(CaptureCollection 類(lèi)的對(duì)象)是作為 Match 和 group 類(lèi)的成員提供的,以便于對(duì)捕獲的子字符串的集合的訪(fǎng)問(wèn)。例如,如果使用正則表達(dá)式 ((a(b))c)+(其中 + 限定符指定一個(gè)或多個(gè)匹配)從字符串"abcabcabc"中捕獲匹配,則子字符串的每一匹配的 Group 的 CaptureCollection 將包含三個(gè)成員。

  下面的程序使用正則表達(dá)式 (Abc)+來(lái)查找字符串"XYZAbcAbcAbcXYZAbcAb"中的一個(gè)或多個(gè)匹配,闡釋了使用 Captures 屬性來(lái)返回多組捕獲的子字符串。

  

  using System;

  using System.Text.RegularExpressions;

  public class RegexTest

  {

   public static void RunTest()

   {

    int counter;

    Match m;

    CaptureCollection cc;

    GroupCollection gc;

    Regex r = new Regex("(Abc)+"); //查找"Abc"

    m = r.Match("XYZAbcAbcAbcXYZAbcAb"); //設(shè)定要查找的字符串

    gc = m.Groups;

    //輸出查找組的數(shù)目

    Console.WriteLine("Captured groups = " + gc.Count.ToString());

    // Loop through each group.

    for (int i=0; i < gc.Count; i++) //查找每一個(gè)組

    {

     cc = gc[i].Captures;

     counter = cc.Count;

     Console.WriteLine("Captures count = " + counter.ToString());

     for (int ii = 0; ii < counter; ii++)

     {

      // Print capture and position.

      Console.WriteLine(cc[ii] + " Starts at character " +

      cc[ii].Index); //輸入捕獲位置

     }

    }

   }

   public static void Main() {

    RunTest();

   }

  }

  此例返回下面的輸出結(jié)果:

  

  Captured groups = 2

  Captures count = 1

  AbcAbcAbc Starts at character 3

  Captures count = 3

  Abc Starts at character 3

  Abc Starts at character 6

  Abc Starts at character 9

  3.6 Capture 類(lèi)包含來(lái)自單個(gè)子表達(dá)式捕獲的結(jié)果

  在 Group 集合中循環(huán),從 Group 的每一成員中提取 Capture 集合,并且將變量 posn 和 length 分別分配給找到每一字符串的初始字符串中的字符位置,以及每一字符串的長(zhǎng)度。

  

  Regex r;

  Match m;

  CaptureCollection cc;

  int posn, length;

  r = new Regex("(abc)*");

  m = r.Match("bcabcabc");

  for (int i=0; m.Groups[i].Value != ""; i++)

  {

   cc = m.Groups[i].Captures;

   for (int j = 0; j < cc.Count; j++)

   {

    posn = cc[j].Index; //捕獲對(duì)象位置

    length = cc[j].Length; //捕獲對(duì)象長(zhǎng)度

   }

}
  
  


  


  把組合字符組合起來(lái)后,每次都會(huì)返回一個(gè)組對(duì)象,就可能并不是我們希望的結(jié)果。如果希望把組合字符作為搜索模式的一部分,就會(huì)有相當(dāng)大的系統(tǒng)開(kāi)銷(xiāo)。對(duì)于單個(gè)的組,可以用以字符序列"?:"開(kāi)頭的組禁止這么做,就像URI樣例那樣。而對(duì)于所有的組,可以在RegEx.Matches()方法上指定RegExOptions.ExplicitCapture標(biāo)志。
 
4、利用正則表達(dá)式實(shí)現(xiàn)字符串搜索

  4.1 在C#中使用.NET一般表達(dá)式引擎

  下面將通過(guò)一個(gè)樣例的開(kāi)發(fā),執(zhí)行并顯示一些搜索的結(jié)果,說(shuō)明一般表達(dá)式的一些特性,以及如何在C#中使用.NET一般表達(dá)式引擎。說(shuō)明使用字符串時(shí)應(yīng)在前面加上符號(hào)@。

  

  String Text=@"I can not find my position in Beijing";

  把這個(gè)文本稱(chēng)為輸入字符串,為了說(shuō)明一般表達(dá)式.NET類(lèi),本文先進(jìn)行一次純文本的搜索,這次搜索不帶任何轉(zhuǎn)義序列或一般表達(dá)式命令。假定要查找所有字符串ion,把這個(gè)搜索字符串稱(chēng)為模式。使用一般表達(dá)式和上面聲明的變量Text,編寫(xiě)出下面的代碼:

  

  String Pattern = "ion";

  MatchCollection Matches = Regex.Matches(Text,Pattern,RegexOptions);

  foreach(Match NextMatch in Matches)

  { Console.WriteLine(NextMatch.Index); }

  在這段代碼中,使用了System.Text.RegularExpressions名稱(chēng)空間中Regex類(lèi)的靜態(tài)方法Match()。這個(gè)方法的參數(shù)是一些輸入文本、一個(gè)模式和RegexOptions每句中的一組可選標(biāo)志。Matches()返回MatchCollection,每個(gè)匹配都用一個(gè)Match對(duì)象來(lái)表示。在上面的代碼中,只是在集合中迭代,使用Match類(lèi)的Index屬性,返回輸入文本中匹配所在的索引。運(yùn)行這段代碼,將得到1個(gè)匹配項(xiàng)。

  一般集合的功能主要取決于模式字符串。原因是模式字符串不僅僅包含純文本。如前所述。還包含元字符和轉(zhuǎn)義序列,元字符是給出命令的特殊字符,而轉(zhuǎn)義序列的工作方式與C#的轉(zhuǎn)義序列相同,它們都是以反斜杠\開(kāi)頭的字符,具有特殊的含義。例如,假定要查找以n開(kāi)頭的字,就可以使用轉(zhuǎn)義序列\(zhòng)b,它表示一個(gè)字的邊界(字的邊界是以某個(gè)字母數(shù)字標(biāo)的字符開(kāi)頭,或者后面是一個(gè)空白字符或標(biāo)點(diǎn)符號(hào)),下面編寫(xiě)如下代碼:

  

  String Pattern = @"\bn";

  MatchCollection Matches = Regex.Matches(Text,Pattern,RegexOptions.IgnoreCase 

  RegexOptions.ExplicitCapture);

  要在運(yùn)行時(shí)把\b傳遞給.NET一般表達(dá)式引擎,反斜杠\不應(yīng)被C#編譯器解釋為轉(zhuǎn)義序列。如果要查找以序列ion結(jié)尾的字,可以使用下面的代碼:

  

  String Pattern = @"ion\b";

  如果要查找以字母n開(kāi)頭,以序列ion結(jié)尾的所有字,需要一個(gè)以\bn開(kāi)頭,以ion\b結(jié)尾的模式,中間內(nèi)容怎么辦?需要告訴計(jì)算機(jī)n和ion中間的內(nèi)容可以是任意長(zhǎng)度的字符,只要字符不是空白即可,正確的模式如下所示:

  

  String Pattern = @"\bn\S*ion\b";

  4.2 特定字符或轉(zhuǎn)義序列

  大多數(shù)重要的正則表達(dá)式語(yǔ)言運(yùn)算符都是非轉(zhuǎn)義的單個(gè)字符。轉(zhuǎn)義符 \(單個(gè)反斜杠)通知正則表達(dá)式分析器反斜杠后面的字符不是運(yùn)算符。例如,分析器將星號(hào) (*) 視為重復(fù)限定符,而將后跟星號(hào)的反斜杠 (\*) 視為 Unicode 字符 002A。

  使用一般表達(dá)式要習(xí)慣的一點(diǎn)是,查看像這樣怪異的字符序列,但這個(gè)序列的工作是非常邏輯化的。轉(zhuǎn)義序列\(zhòng)S表示任何不適空白的字符。*稱(chēng)為數(shù)量詞,其含義是前面的字符可以重復(fù)任意次,包括0次。序列\(zhòng)S*表示任何不適空白的字符。因此,上面的模式匹配于以n開(kāi)頭,以ion結(jié)尾的任何單個(gè)字。下表中列出的字符轉(zhuǎn)義在正則表達(dá)式和替換模式中都會(huì)被識(shí)別。
表1:特定字符或轉(zhuǎn)義序列

  

  特定字符或轉(zhuǎn)義序列 含義 樣例 匹配的樣例

  ^ 輸入文本的開(kāi)頭 ^B B,但只能是文本中的第一個(gè)字符

  $ 輸入文本的結(jié)尾 X$ X,但只能是文本中的最后一個(gè)字符

  . 除了換行字符(\n)以外的所有單個(gè)字符 i.ation isation、ization

  * 可以重復(fù)0次或多次的前導(dǎo)字符 ra*t rat、raat等

  + 可以重復(fù)1次或多次的前導(dǎo)字符 ra+t rt、rat、raat等

 ??? 可以重復(fù)0次或1次的前導(dǎo)字符 ra?t 只有rt和rat匹配

  \s 任何空白字符 \sa [space]a,\ta,\na(\t和\n與C#的\t和\n含義相同)

  \S 任何不是空白的字符 \SF aF,rF,cF,但不能是\tf

  \b 字邊界 ion\b 以ion結(jié)尾的任何字

  \B 不是字邊界的位置 \BX\B 字中間的任何X

  如果要搜索一個(gè)元字符,也可以通過(guò)帶有反斜杠的轉(zhuǎn)義字符來(lái)表示。例如,.表示除了換行字符以外的任何字符,而\.表示一個(gè)點(diǎn)。

  可以把可替換的字符放在方括號(hào)中,請(qǐng)求匹配包含這些字符。例如,[1 c]表示字符可以是1或者是c。如果要搜索map或者man,可以使用序列"ma[n p]"(僅指引號(hào)內(nèi)字符,下面雷同)。在方括號(hào)中,也可以制定一個(gè)范圍,例如"[a-z]"表示所有的小寫(xiě)字母(使用連字號(hào) (-) 允許指定連續(xù)字符范圍),"[B-F]"表示B到F之間的所有大寫(xiě)字母,"[0-9]"表示一個(gè)數(shù)字,如果要搜索一個(gè)整數(shù)(該序列只包含0到9的字符),就可以編寫(xiě)"[0-9]+"(注意,使用+字符表示至少要有這樣一個(gè)數(shù)字,但可以有多個(gè)數(shù)字,所以9、83和3443等都是匹配的。)

  下面看看一般表達(dá)式的結(jié)果,編寫(xiě)一個(gè)實(shí)例RegularExpressionsZzy。建立幾個(gè)一般表達(dá)式,顯示其結(jié)果,讓用戶(hù)了解一下表達(dá)式是如何工作的。

  該實(shí)例的核心是一個(gè)方法WriteMatches(),它把MatchCollection中的所有匹配以比較詳細(xì)的方式顯示出來(lái)。對(duì)于每個(gè)匹配,它都會(huì)顯示該匹配在輸入字符串中所在的索引,匹配的字符串和一個(gè)略長(zhǎng)的字符串,其中包含輸入文本中至多8個(gè)外圍字符,其中至少有5個(gè)字符放在匹配的前面,至多5個(gè)字符放在匹配的后面(如果匹配的位置在輸入文本的開(kāi)頭或結(jié)尾5個(gè)字符內(nèi),則結(jié)果中匹配前后的字符就會(huì)少于4個(gè))。換言之,靠近輸入文本末尾的匹配應(yīng)是"and messaging ofd",匹配的前后各有5個(gè)字符,但位于輸入文本的最后一個(gè)字上的匹配就應(yīng)是"g of data",匹配的字后只有一個(gè)字符。因?yàn)樵谠撟址暮竺媸亲址慕Y(jié)尾。這個(gè)長(zhǎng)字符串可以更清楚地表明一般表達(dá)式是在什么地方查找到匹配的:

  

  static void WriteMatches(string text, MatchCollection matches)

  {

   Console.WriteLine("Original text was: \n\n" + text + "\n");

   Console.WriteLine("No. of matches: " + matches.Count);

   foreach (Match nextMatch in matches)

   {

    int Index = nextMatch.Index;

    string result = nextMatch.ToString();

    int charsBefore = (Index < 5) ? Index : 5;

    int fromEnd = text.Length - Index - result.Length;

    int charsAfter = (fromEnd < 5) ? fromEnd : 5;

    int charsToDisplay = charsBefore + charsAfter + result.Length;

    Console.WriteLine("Index: {0}, \tString: {1}, \t{2}",Index, result,

    text.Substring(Index - charsBefore, charsToDisplay));

   }

  }

  在這個(gè)方法中,處理過(guò)程是確定在較長(zhǎng)的字符串中有多少個(gè)字符可以顯示,而無(wú)需超限輸入文本的開(kāi)頭或結(jié)尾。注意在Match對(duì)象上使用了另一個(gè)屬性Value,它包含標(biāo)識(shí)該匹配的字符串,而且,RegularExpressionsZzy只包含名為Find_po,F(xiàn)ind_n等的方法,這些方法根據(jù)本文執(zhí)行某些搜索操作。

  4.3 正則表達(dá)式選項(xiàng)

  可以使用影響匹配行為的選項(xiàng)修改正則表達(dá)式模式??梢酝ㄟ^(guò)兩種基本方法設(shè)置正則表達(dá)式選項(xiàng):其一是可以在 Regex(pattern, options) 構(gòu)造函數(shù)中的 options 參數(shù)中指定,其中 options 是 RegexOptions 枚舉值的按位"或"組合;其二是使用內(nèi)聯(lián) (?imnsx-imnsx:) 分組構(gòu)造或 (?imnsx-imnsx) 其他構(gòu)造在正則表達(dá)式模式內(nèi)設(shè)置它們。

  在內(nèi)聯(lián)選項(xiàng)構(gòu)造中,一個(gè)選項(xiàng)或一組選項(xiàng)前面的減號(hào) (-) 用于關(guān)閉這些選項(xiàng)。例如,內(nèi)聯(lián)構(gòu)造 (?ix-ms) 將打開(kāi) IgnoreCase 和 IgnorePatternWhiteSpace 選項(xiàng)而關(guān)閉 Multiline 和 Singleline 選項(xiàng)。

  表2:RegexOptions 枚舉的成員以及等效的內(nèi)聯(lián)選項(xiàng)字符

  

  RegexOption 成員 內(nèi)聯(lián)字符 說(shuō)明

  None 無(wú) 指定不設(shè)置任何選項(xiàng)。

  IgnoreCase i 指定不區(qū)分大小寫(xiě)的匹配。

  Multiline m 指定多行模式。更改 ^ 和 $ 的含義,以使它們分別與任何行的開(kāi)頭和結(jié)尾匹配,而不只是與整個(gè)字符串的開(kāi)頭和結(jié)尾匹配。

  ExplicitCapture n 指定唯一有效的捕獲是顯式命名或編號(hào)的 (?...) 形式的組。這允許圓括號(hào)充當(dāng)非捕獲組,從而避免了由 (?:...) 導(dǎo)致的語(yǔ)法上的笨拙。

  Compiled 無(wú) 指定正則表達(dá)式將被編譯為程序集。生成該正則表達(dá)式的 Microsoft 中間語(yǔ)言 (MSIL) 代碼;以較長(zhǎng)的啟動(dòng)時(shí)間為代價(jià),得到更快的執(zhí)行速度。

  Singleline s 指定單行模式。更改句點(diǎn)字符 (.) 的含義,以使它與每個(gè)字符(而不是除 \n 外的所有字符)匹配。

  IgnorePatternWhitespace x 指定從模式中排除非轉(zhuǎn)義空白并啟用數(shù)字符號(hào) (#) 后面的注釋。請(qǐng)注意,空白永遠(yuǎn)不會(huì)從字符類(lèi)中消除。

  RightToLeft 無(wú) 指定搜索是從右向左而不是從左向右進(jìn)行的。具有此選項(xiàng)的正則表達(dá)式將移動(dòng)到起始位置的左邊而不是右邊。(因此,起始位置應(yīng)指定為字符串的結(jié)尾而不是開(kāi)頭。)為了避免構(gòu)造具有無(wú)限循環(huán)的正則表達(dá)式的可能性,此選項(xiàng)不能在中流指定。但是,(?<) 回顧后發(fā)構(gòu)造提供了可用作子表達(dá)式的類(lèi)似替代物。

  ECMAScript 無(wú) 指定已為表達(dá)式啟用了符合 ECMAScript 的行為。此選項(xiàng)僅可與 IgnoreCase 和 Multiline 標(biāo)志一起使用。將 ECMAScript 同任何其他標(biāo)志一起使用將導(dǎo)致異常。

  例如,F(xiàn)ind_po在字開(kāi)頭處查找以"po"開(kāi)頭的字符串:

  

  static void Find_po()

  {

   string text = @" I can not find my position in Beijing ";

   string pattern = @"\bpo\S*ion\b";

   MatchCollection matches = Regex.Matches(text, pattern, RegexOptions.IgnoreCase

    RegexOptions.IgnorePatternWhitespace   RegexOptions.ExplicitCapture);

   WriteMatches(text, matches);

  }

  這段代碼還使用了名稱(chēng)空間RegularExpressions:

  

  using System;

  using System.Text.RegularExpressions;

  4.4 匹配、組和捕獲

  一般表達(dá)式的一個(gè)很好的特性是可以把字符組合起來(lái),方式與C#中的復(fù)合語(yǔ)句一樣。在C#中,可以通過(guò)把任意數(shù)量的語(yǔ)句放在花括號(hào)中的方式把它們組合在一起。其結(jié)果就像一個(gè)復(fù)合語(yǔ)句那樣。在一般表達(dá)式模式中,也可以把任何字符組合起來(lái)(包括元字符和轉(zhuǎn)義序列),像處理一個(gè)字符那樣處理它們。唯一的區(qū)別是要使用圓括號(hào),而不是花括號(hào),得到的序列成為一個(gè)組。

  例如,模式"(an)+"定位序列an的任以重復(fù)。量詞+只應(yīng)用于它前面的一個(gè)字符,但因?yàn)槲覀儼炎址M合起來(lái)了,所以它現(xiàn)在把重復(fù)的an作為一個(gè)單元來(lái)對(duì)待。"(an)."應(yīng)用到輸入文本"bananas came to Europe late in the annals of history"上,會(huì)從bananas中選擇出anan。另一方面,如果使用an+,則將從annals中選擇ann,從bananas中選擇出兩個(gè)an。為什么(an)+選擇的是anan,而沒(méi)有把單個(gè)的an作為一個(gè)匹配。匹配規(guī)則是不能重復(fù)的,如果有可能重復(fù),在默認(rèn)情況下就選擇較長(zhǎng)的匹配。

  但是,組的功能要比這強(qiáng)大得多。在默認(rèn)情況下,把模式的一部分組合為一個(gè)組時(shí),就要求一般表達(dá)式引擎記住可以按照這個(gè)組來(lái)匹配,也可以按照整個(gè)模式來(lái)匹配。換言之,可以把組當(dāng)作一個(gè)要匹配的模式,如果要把字符串分解為各個(gè)部分,這種模式就是非常有效的。

  例如,URI的格式是" :// : ",其中端口是可選的。它的一個(gè)樣例是http://www.:8080。假定要從一個(gè)URI中提取協(xié)議、地址和端口,而且緊鄰URI的后面可能有空白(但沒(méi)有標(biāo)點(diǎn)符號(hào)),就可以使用下面的表達(dá)式:"\b(\S+)://(\S+)(?::(\S+))?\b"

  該表達(dá)式的工作方式如下:首先,前導(dǎo)和尾部的\b序列確保只需要考慮完全是字的文本部分,在這個(gè)文本部分中,第一組"(\S+)://"會(huì)選擇一個(gè)或多個(gè)不適空白的字符,其后是"://"。在HTTPURI的開(kāi)頭會(huì)選擇出http://?;ɡㄌ?hào)表示把http存儲(chǔ)為一個(gè)組。后面的"(\S+)"則在上述URI中選擇www. ,這個(gè)組在遇到詞的結(jié)尾時(shí)或標(biāo)記另一個(gè)組的冒號(hào)"(:)"時(shí)結(jié)束。

  下一個(gè)組選擇端口(本例是:8080)。后面的?表示這個(gè)組在匹配中是可選的,如果沒(méi)有:xxxx,也不會(huì)妨礙匹配的標(biāo)記。

  這是非常重要的,因?yàn)槎丝谠赨RI中一般不指定,實(shí)際上,在大多數(shù)情況下,URI是沒(méi)有端口號(hào)的。但是,事情會(huì)比較復(fù)雜。如果要求冒號(hào)可以出現(xiàn),也可以不出現(xiàn),但不希望把這個(gè)冒號(hào)也存儲(chǔ)在組中。為此,可以嵌套兩個(gè)組:內(nèi)部的"(\S+)"組選擇冒號(hào)后面的內(nèi)容(本例中是8080),外面的組包含內(nèi)部的組,后面是一個(gè)冒號(hào),該冒號(hào)又在序列"?:"的后面。這個(gè)序列表示該組不應(yīng)保存(只需要保存"8080",不需要保存":8080")。不要把這兩個(gè)冒號(hào)混淆了,第一個(gè)冒號(hào)是序列"?:"的一部分,表示不保存這個(gè)組,第二個(gè)冒號(hào)是要搜索的文本。

  在這個(gè)字符串上運(yùn)行該模式:I always visit http://www. 得到的匹配是http://www. 。在這個(gè)匹配中,僅提到了三個(gè)組,還有第四個(gè)組表示匹配本身。理論上,每個(gè)組都可以選擇0次、1次或者多次匹配。單個(gè)的匹配就稱(chēng)為捕獲。在第一個(gè)組"(\S+)",有一個(gè)捕獲http。第二個(gè)組也有一個(gè)捕獲www. ,但第三個(gè)組沒(méi)有捕獲,因?yàn)樵谶@個(gè)URI中沒(méi)有端口號(hào)。注意該字符串在其本身上包含第二個(gè)http://。雖然它匹配于第一個(gè)組,但不會(huì)被搜索出來(lái),因?yàn)檎麄€(gè)搜索表達(dá)式不匹配于這部分文本。

  再比如下面這個(gè)例子,以下代碼示例使用 Match.Result 來(lái)從 URL提取協(xié)議和端口號(hào)。例如,"http://www.:8080/index.html"將返回"http:8080"。

  

  String Extension(String url)

  {

   Regex r = new Regex(@"^(? \w+)://[^/]+?(? :\d+)?/",

   RegexOptions.Compiled);

   return r.Match(url).Result("${proto}${port}");

  }

  5、小結(jié)

  .NET 框架正則表達(dá)式類(lèi)是基類(lèi)庫(kù)的一部分,并且可以和面向公共語(yǔ)言運(yùn)行庫(kù)的任何語(yǔ)言或工具(包括 ASP.NET和 Visual Studio .NET)一起使用。本文給出了在C#下利用正則表達(dá)式實(shí)現(xiàn)字符串搜索功能的方法,通過(guò)對(duì).NET框架下的正則表達(dá)式的研究及實(shí)例分析,總結(jié)了正則表達(dá)式的規(guī)則、選項(xiàng)等,方便以后朋友們的應(yīng)用。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多