swollaws
漂泊中体会不到生活的味道,那是因为吃不到老妈烧的饭。

一、正则表达式概述

      正则表达式语言是一种专门用于字符串处理的语言。正则表达式字符串初看起来像是一般的字符串,但其中包含了元字符和转义序列----元字符是给出命令的特定字符,而转义序列的工作方式与C#的转义序列相同,它们都是以反斜杠\开头的字符,具有特殊的含义。下面附上一份自己记录的Regexp常用元字符和转义序列https://files.cnblogs.com/swollaws/RegExp.rar

      让我们先看看一个只搜索纯文本的简单示例

 

  1. static void Check()
  2. {
  3.     string text = @"XML has made a major impact in almost every aspect of software
  4.                 development. Designed as an open, extensible, self-describing language,
  5.                 it has become the standard for data and document delivery on the web.
  6.                 The panoply of XML-related technologies continues to develop at breakneck
  7.                 speed, to enable validation, navigation, transformation, linking, querying, description, and messaging of data.";
  8.     string pattern = @"ion";
  9.     MatchCollection matches = Regex.Matches(text, pattern, RegexOptions.IgnoreCase);
  10.     foreach (Match match in matches)
  11.     {
  12.         Console.WriteLine(match.Index);
  13.     }
  14. } 

      其中第三行定义的字符串称为输入字符串,第八行定义的字符串称为模式。而第九行则是使用System.Text.RegularExpressions命名空间中Regex类的静态方法Matches()。这个方法的参数是一些输入文本、一个模式和RegexOptions枚举中的一组可选标志。匹配是一种技术术语,表示在表达式中查找模式实例的结果,用System.Text.RegularExpressions.Match来代表。因此,上面示例中我们返回一个包含所有匹配的MatchCollection,每个匹配都用一个Match对象来表示。

      注意:如果要搜索一个元字符,也可以通过带有反斜杠的转义字符来表示。例如,.(一个句点)表示除了换行字符以外的任何字符,而\.表示一个点。

      简单的示例      

  1. using System;
  2. using System.Text.RegularExpressions;
  3.  
  4. namespace Text
  5. {
  6.     class RegExp
  7.     {
  8.         static void Main()
  9.         {
  10.             string text = @"XML has made a major impact in almost every aspect of software development. Designed as an open, extensible, self-describing language, it has become the standard for data and document delivery on the web. The panoply of XML-related technologies continues to develop at breakneck speed, to enable validation, navigation, transformation, linking, querying, description, and messaging of data.";
  11.  
  12.             string pattern = @"\bn\S*ion\b";//注意字符串前面的符号@。要在运行时把\b传递给.NET正则表达式引擎,反斜杠\不应被C#编译器解释为转义序列。
  13.  
  14.             MatchCollection matches = Regex.Matches(text, pattern,
  15.                                                     RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace |
  16.                                                     RegexOptions.ExplicitCapture);
  17.             WriteMatches(text, matches);
  18.             Console.ReadLine();
  19.         }
  20.  
  21.         static void WriteMatches(string text, MatchCollection matches)
  22.         {
  23.             Console.WriteLine("Original text was: \n\n" + text + "\n");
  24.             Console.WriteLine("No. of matches: " + matches.Count);
  25.             foreach (Match nextMatch in matches)
  26.             {
  27.                 int Index = nextMatch.Index;//该匹配项在输入字符串中的索引
  28.                 string result = nextMatch.ToString();//匹配的字符串
  29.                 int charsBefore = (Index < 5) ? Index : 5;
  30.                 int fromEnd = text.Length - Index - result.Length;
  31.                 int charsAfter = (fromEnd < 5) ? fromEnd : 5;
  32.                 int charsToDisplay = charsBefore + charsAfter + result.Length;
  33.  
  34.                 Console.WriteLine("Index: {0}, \tString: {1}, \t{2}", Index, result,
  35.                                   text.Substring(Index - charsBefore, charsToDisplay));
  36.             }
  37.         }
  38.     }
  39. }

二、匹配、组合和捕获

      在正则表达式模式中,也可以把任何字符组合起来,像处理一个字符那样处理它们。唯一的区别是要使用圆括号,而不是花括号,得到的序列称为一个组,例如,模式(an)+定位序列an的任意重复。量词+只应用于它前面的一个字符,但因为我们把字符组合起来了,所以它现在把重复的an作为一个但原来对待。(an)+应用到输入文本bananas came to Europe late in the annals of history上,会从bananas中选择出anan。

      在默认情况下,把模式的一部分组合为一个组时,就要求正则表达式引擎按照这个组来匹配,或按照整个模式来匹配。换言之,可以把组当作一个要匹配的模式来返回,如果要把字符串分解为各个部分,这种模式就是非常有效地。

      例如,URI的格式是<protocol>://<address>:<port>,其中端口是可选的。它的一个示例是http://www.wrox.com:4355/。假定要从一个URI中提取协议、地址和端口,就可以使用下面的表达式:\b(\S+)://(\S+)(?::(\S+))?\b。该表达式的工作方式如下:首先,前导和尾部的\b序列确保只需要考虑完全是字的文本部分,在这个文本部分中,第一组(\S+)://会选择一个或多个不是空白的字符,其后是://。在URI的开头会选择出http://。花括号表示把http存储为一个组。后面的序列(\S+)则在上述URI中选择http://www.worx.com/,这个组在遇到词的结尾(结束\b)时或标记另一个组的冒号(:)时结束。下一个组选择端口(本例是:4355)。后面的?表示这个组在匹配中是可选的。但是,事情会比较复杂。我们希望指定冒号可以出现,也可以不出现,但不希望把这个冒号也存储在组中。为此,可以嵌套两个组:内部的(\S+)组选择冒号后面的内容(本例中是4355),外面的组包含内部的组,前面是一个冒号,该组又在序列?:的后面。这个序列表示该组不应保存(只需要保存4355,不需要保存:4355)。不要把这两个冒号混淆了,第一个冒号是序列?:的一部分,表示不保存这个组,第二个冒号是要搜索的文本。

      在下面的字符串上运行该模式,得到的匹配是http://www.wrox.com/。Hey I've just found this amazing URI at http:// what was it-oh yes http://www.wrox.com/。在这个匹配中,找到了刚才提及的3个组,还有第四个组表示匹配本身。单个的匹配就称为捕获。在第一个组(\S+)中,有一个捕获http,第二个组也有一个捕获http://www.wrox.com/,但第三个组没有捕获,因为在这个RUI中没有端口号。

      在C#的System.Text.RegularExpressions命名空间中,Group和Capture类支持组合捕获。GroupCollection和CaptureCollection分别表示组和捕获的集合,Match类有一个方法Groups(),它返回相应的GroupCollection对象,Group类也相应地执行一个方法Captures(),它返回CaptureCollection对象。

      把一些字符组合起来后,每次都会返回一个Group对象。如果只是希望把一些字符组合起来,作为搜索模式的一部分,实例化对象就会浪费相当大的系统开销。对于单个的组,可以用以字符序列?:开头,禁止实例化对象,就像URI示例那样。而对于所有的组,可以在Regex.Matches()方法上指定RegexOptions.ExplicitCapture标志。

 

 

 

posted on 2009-07-12 18:50  swollaw  阅读(267)  评论(0编辑  收藏  举报