正则表达式构造与测试小工具(上)
前言
        
        最初接触到正则表达式是在大一时准备高程考试的时候,那时候只知道这个东西可以拿来对对给定的语句进行匹配,可对它很多的东西都不了解。在学习了C#后,终于有机会接触到这方面的细节了,其实我用过的方面也不多,回想起来也就有几个地方用过:比如用户注册时判断email地址是否合法,手机号码,身份证号码是否符合格式,用户名和密码的限制等,再有就是在做一些文本的搜索与替换,当然字符串处理的很多方面都会用到。
正则表达式提供了功能强大、灵活而又高效的方法来处理文本。正则表达式的全面模式匹配表示法使您可以快速地分析大量的文本以找到特定的字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合以生成报告。对于处理字符串(例如 HTML 处理、日志文件分析和 HTTP 标头分析)的许多应用程序而言,正则表达式是不可缺少的工具。
       我们可能比较熟悉在 DOS 文件系统中使用的 ? 和 * 元字符,这两个元字符分别代表任意单个字符和字符组。DOS 文件命令 COPY *.DOC A: 命令文件系统将文件扩展名为 .DOC 的所有文件均复制到 A 驱动器的磁盘中。元字符 * 代表文件扩展名 .DOC 前的任何文件名。
以下简单介绍下 .NET Framework 中用到的正则表达式类。
Regex
Regex 类表示不可变(只读)正则表达式类。它还包含各种静态方法,允许在不显式创建其他类的实例的情况下使用其他正则表达式类。
以下代码示例创建了 Regex 类的实例并在初始化对象时定义一个简单的正则表达式。请注意,使用了附加的反斜杠作为转义字符,它将 \s 匹配字符类中的反斜杠指定为原义字符。
 // Declare object variable of type Regex.
// Declare object variable of type Regex.
 Regex r;
    Regex r; 
 // Create a Regex object and define its regular expression.
    // Create a Regex object and define its regular expression.
 r = new Regex("\\s2000");
    r = new Regex("\\s2000");

Match
Match 类表示正则表达式匹配操作的结果。以下示例使用 Regex 类的 Match 方法返回 Match 类型的对象,以便找到输入字符串中的第一个匹配项。此示例使用 Match 类的 Match.Success 属性来指示是否已找到匹配。
 // Create a new Regex object.
// Create a new Regex object.
 Regex r = new Regex("abc");
    Regex r = new Regex("abc"); 
 // Find a single match in the string.
    // Find a single match in the string.
 Match m = r.Match("123abc456");
    Match m = r.Match("123abc456"); 
 if (m.Success)
    if (m.Success) 
 {
    {
 // Print out the character position where a match was found.
        // Print out the character position where a match was found. 
 // (Character position 3 in this case.)
        // (Character position 3 in this case.)
 Console.WriteLine("Found match at position " + m.Index);
        Console.WriteLine("Found match at position " + m.Index);
 }
    }

MatchCollection
MatchCollection 类表示成功的非重叠匹配的序列。该集合为不可变(只读)的,并且没有公共构造函数。MatchCollection 的实例是由 Regex.Matches 属性返回的。
以下示例使用 Regex 类的 Matches 方法,通过在输入字符串中找到的所有匹配填充 MatchCollection。该示例将此集合复制到一个字符串数组和一个整数数组中,其中字符串数组用以保存每个匹配项,整数数组用以指示每个匹配项的位置。
 MatchCollection mc;
MatchCollection mc;
 String[] results = new String[20];
    String[] results = new String[20];
 int[] matchposition = new int[20];
    int[] matchposition = new int[20];
 
    
 // Create a new Regex object and define the regular expression.
    // Create a new Regex object and define the regular expression.
 Regex r = new Regex("abc");
    Regex r = new Regex("abc"); 
 // Use the Matches method to find all matches in the input string.
    // Use the Matches method to find all matches in the input string.
 mc = r.Matches("123abc4abcd");
    mc = r.Matches("123abc4abcd");
 // Loop through the match collection to retrieve all
    // Loop through the match collection to retrieve all 
 // matches and positions.
    // matches and positions.
 for (int i = 0; i < mc.Count; i++)
    for (int i = 0; i < mc.Count; i++) 
 {
    {
 // Add the match string to the string array.
        // Add the match string to the string array.   
 results[i] = mc[i].Value;
        results[i] = mc[i].Value;
 // Record the character position where the match was found.
        // Record the character position where the match was found.
 matchposition[i] = mc[i].Index;
        matchposition[i] = mc[i].Index;   
 }
    }

GroupCollection
GroupCollection 类表示捕获的组的集合并返回单个匹配中捕获的组的集合。该集合为不可变(只读)的,并且没有公共构造函数。GroupCollection 的实例在 Match.Groups 属性返回的集合中返回。
以下控制台应用程序示例查找并输出由正则表达式捕获的组的数目。有关如何提取组集合的每一成员中的各个捕获项的示例,请参见下面一节的 Capture Collection 示例。
 using System;
  using System;
 using System.Text.RegularExpressions;
    using System.Text.RegularExpressions;
 
 
 public class RegexTest
    public class RegexTest 
 {
    {
 public static void RunTest()
        public static void RunTest() 
 {
        {
 // Define groups "abc", "ab", and "b".
            // Define groups "abc", "ab", and "b".
 Regex r = new Regex("(a(b))c");
            Regex r = new Regex("(a(b))c"); 
 Match m = r.Match("abdabc");
            Match m = r.Match("abdabc");
 Console.WriteLine("Number of groups found = " + m.Groups.Count);
            Console.WriteLine("Number of groups found = " + m.Groups.Count);
 }
        }
 public static void Main()
        public static void Main() 
 {
        {
 RunTest();
            RunTest();
 }
        }
 }
    }
该示例产生下面的输出。
 Number of groups found = 3
Number of groups found = 3
CaptureCollection
CaptureCollection 类表示捕获的子字符串的序列,并且返回由单个捕获组执行的捕获的集合。由于限定符,捕获组可以在单个匹配中捕获多个字符串。Captures 属性(CaptureCollection 类的对象)是作为 Match 和 group 类的成员提供的,以便于对捕获的子字符串的集合的访问。
例如,如果使用正则表达式 ((a(b))c)+(其中 + 限定符指定一个或多个匹配)从字符串“abcabcabc”中捕获匹配,则子字符串的每一匹配的 Group 的 CaptureCollection 将包含三个成员。
以下控制台应用程序示例使用正则表达式 (Abc)+ 来查找字符串“XYZAbcAbcAbcXYZAbcAb”中的一个或多个匹配。该示例阐释了使用 Captures 属性来返回多组捕获的子字符串。
 using System;
using System;
 using System.Text.RegularExpressions;
    using System.Text.RegularExpressions;
 
 
 public class RegexTest
    public class RegexTest 
 {
        {
 public static void RunTest()
        public static void RunTest() 
 {
        {
 int counter;
            int counter;
 Match m;
            Match m;
 CaptureCollection cc;
            CaptureCollection cc;
 GroupCollection gc;
            GroupCollection gc;
 
 
 // Look for groupings of "Abc".
            // Look for groupings of "Abc".
 Regex r = new Regex("(Abc)+");
            Regex r = new Regex("(Abc)+"); 
 // Define the string to search.
            // Define the string to search.
 m = r.Match("XYZAbcAbcAbcXYZAbcAb");
            m = r.Match("XYZAbcAbcAbcXYZAbcAb"); 
 gc = m.Groups;
            gc = m.Groups;
 
 
 // Print the number of groups.
            // Print the number of groups.
 Console.WriteLine("Captured groups = " + gc.Count.ToString());
            Console.WriteLine("Captured groups = " + gc.Count.ToString());
 
 
 // Loop through each group.
            // Loop through each group.
 for (int i=0; i < gc.Count; i++)
            for (int i=0; i < gc.Count; i++) 
 {
            {
 cc = gc[i].Captures;
                cc = gc[i].Captures;
 counter = cc.Count;
                counter = cc.Count;
 
                
 // Print number of captures in this group.
                // Print number of captures in this group.
 Console.WriteLine("Captures count = " + counter.ToString());
                Console.WriteLine("Captures count = " + counter.ToString());
 
                
 // Loop through each capture in group.
                // Loop through each capture in group.
 for (int ii = 0; ii < counter; ii++)
                for (int ii = 0; ii < counter; ii++) 
 {
                {
 // Print capture and position.
                    // Print capture and position.
 Console.WriteLine(cc[ii] + "   Starts at character " +
                    Console.WriteLine(cc[ii] + "   Starts at character " + 
 cc[ii].Index);
                        cc[ii].Index);
 }
                }
 }
            }
 }
        }
 
 
 public static void Main() {
        public static void Main() {
 RunTest();
            RunTest();
 }
        }
 }
    }

此示例返回下面的输出结果。
 Captured groups = 2
 Captured groups = 2
 Captures count = 1
    Captures count = 1
 AbcAbcAbc   Starts at character 3
    AbcAbcAbc   Starts at character 3
 Captures count = 3
    Captures count = 3
 Abc   Starts at character 3
    Abc   Starts at character 3
 Abc   Starts at character 6
    Abc   Starts at character 6
 Abc   Starts at character 9
    Abc   Starts at character 9

Group
group 类表示来自单个捕获组的结果。因为 Group 可以在单个匹配中捕获零个、一个或更多的字符串(使用限定符),所以它包含 Capture 对象的集合。因为 Group 继承自 Capture,所以可以直接访问最后捕获的子字符串(Group 实例本身等价于 Captures 属性返回的集合的最后一项)。
Group 的实例是由 Match.Groups(groupnum) 属性返回的,或者在使用“(?<groupname>)”分组构造的情况下,是由 Match.Groups("groupname") 属性返回的。
以下代码示例使用嵌套的分组构造来将子字符串捕获到组中。
 int[] matchposition = new int[20];
 int[] matchposition = new int[20];
 String[] results = new String[20];
    String[] results = new String[20];
 // Define substrings abc, ab, b.
    // Define substrings abc, ab, b.
 Regex r = new Regex("(a(b))c");
    Regex r = new Regex("(a(b))c"); 
 Match m = r.Match("abdabc");
    Match m = r.Match("abdabc");
 for (int i = 0; m.Groups[i].Value != ""; i++)
    for (int i = 0; m.Groups[i].Value != ""; i++) 
 {
    {
 // Copy groups to string array.
        // Copy groups to string array.
 results[i]=m.Groups[i].Value;
        results[i]=m.Groups[i].Value; 
 // Record character position.
        // Record character position.
 matchposition[i] = m.Groups[i].Index;
        matchposition[i] = m.Groups[i].Index; 
 }
    }

此示例返回下面的输出结果。
 results[0] = "abc"   matchposition[0] = 3
 results[0] = "abc"   matchposition[0] = 3
 results[1] = "ab"    matchposition[1] = 3
    results[1] = "ab"    matchposition[1] = 3
 results[2] = "b"     matchposition[2] = 4
    results[2] = "b"     matchposition[2] = 4

以下代码示例使用命名的分组构造,从包含“DATANAME:VALUE”格式的数据的字符串中捕获子字符串,正则表达式通过冒号“:”拆分数据。
 Regex r = new Regex("^(?<name>\\w+):(?<value>\\w+)");
  Regex r = new Regex("^(?<name>\\w+):(?<value>\\w+)");
 Match m = r.Match("Section1:119900");
    Match m = r.Match("Section1:119900");

此正则表达式返回下面的输出结果。
 m.Groups["name"].Value = "Section1"
 m.Groups["name"].Value = "Section1"
 m.Groups["value"].Value = "119900"
    m.Groups["value"].Value = "119900"

Capture
Capture 类包含来自单个子表达式捕获的结果。
以下示例在 Group 集合中循环,从 Group 的每一成员中提取 Capture 集合,并且将变量 posn 和 length 分别分配给找到每一字符串的初始字符串中的字符位置,以及每一字符串的长度。
 Regex r;
Regex r;
 Match m;
    Match m;
 CaptureCollection cc;
    CaptureCollection cc;
 int posn, length;
    int posn, length;
 
 
 r = new Regex("(abc)*");
    r = new Regex("(abc)*");
 m = r.Match("bcabcabc");
    m = r.Match("bcabcabc");
 for (int i=0; m.Groups[i].Value != ""; i++)
    for (int i=0; m.Groups[i].Value != ""; i++) 
 {
    {
 // Capture the Collection for Group(i).
        // Capture the Collection for Group(i).
 cc = m.Groups[i].Captures;
        cc = m.Groups[i].Captures; 
 for (int j = 0; j < cc.Count; j++)
        for (int j = 0; j < cc.Count; j++) 
 {
        {
 // Position of Capture object.
            // Position of Capture object.
 posn = cc[j].Index;
            posn = cc[j].Index; 
 // Length of Capture object.
            // Length of Capture object.
 length = cc[j].Length;
            length = cc[j].Length; 
 }
        }
 }
}

在以前编程中用到正则表达式时,总是需要在代码中来对构造出的正则表达式进行测试,不断重复进行着构造—测试---修改---测试的麻烦工作,而项目文件过大时编译一次真不是件舒服的事情,我就想到自己做一个小工具用来构造和测试正则表达式,并且产生相应的代码,这样就可以直接用到项目中来了,从而避免这些烦人的工作了。因此我目标分为如下两部分:1)对构造的正则表达式进行测试,如果测试成功就产生相应的代码。2)通过一些GUI来自动构造正则表达式子(当然这部分我还不大熟)。
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
posted on 2006-07-31 20:00 Phinecos(洞庭散人) 阅读(583) 评论(0) 收藏 举报
 
                     
                    
                 
                    
                 
    
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号 
