C# 正则表达式:轻松提取匹配项并按行显示 – wiki基地

C# 正则表达式:轻松提取匹配项并按行显示

正则表达式,作为一种强大的文本处理工具,在C#开发中扮演着至关重要的角色。它允许我们通过定义模式来搜索、验证、提取和替换字符串中的特定内容。本文将深入探讨C#中正则表达式的用法,重点讲解如何提取匹配项并按行显示,并通过丰富的示例代码和详尽的解释,帮助读者掌握这一实用技巧。

一、C# 正则表达式基础

在C#中使用正则表达式,主要依赖于 System.Text.RegularExpressions 命名空间下的 Regex 类。理解 Regex 类的常用方法和选项是使用正则表达式的基础。

1. Regex 类常用方法

  • Match(string input): 在输入字符串中搜索第一个匹配项。返回 Match 对象,包含匹配结果的信息。
  • Matches(string input): 在输入字符串中搜索所有匹配项。返回 MatchCollection 对象,包含所有 Match 对象的集合。
  • IsMatch(string input): 判断输入字符串中是否存在匹配项。返回布尔值,表示是否匹配。
  • Replace(string input, string replacement): 替换输入字符串中所有匹配项为指定的字符串。返回替换后的字符串。
  • Split(string input): 根据正则表达式将输入字符串分割成字符串数组。返回字符串数组。
  • Escape(string str): 转义字符串中的特殊字符,使其可以作为正则表达式中的字面量使用。
  • Unescape(string str): 取消转义字符串中的转义字符。

2. 正则表达式语法

掌握正则表达式的语法是至关重要的。以下是一些常用的正则表达式元字符和符号:

  • . (点): 匹配除换行符之外的任何单个字符。
  • ^ (脱字符): 匹配字符串的开头。
  • $ (美元符号): 匹配字符串的结尾。
  • [] (字符集): 匹配字符集中的任何单个字符。例如,[abc] 匹配 ‘a’、’b’ 或 ‘c’。
  • [^] (否定字符集): 匹配不在字符集中的任何单个字符。例如,[^abc] 匹配除 ‘a’、’b’ 或 ‘c’ 之外的任何字符。
  • * (星号): 匹配前面的字符零次或多次。
  • + (加号): 匹配前面的字符一次或多次。
  • ? (问号): 匹配前面的字符零次或一次。
  • {n} (量词): 匹配前面的字符恰好 n 次。例如,a{3} 匹配 “aaa”。
  • {n,} (量词): 匹配前面的字符至少 n 次。例如,a{2,} 匹配 “aa”、”aaa”、”aaaa” 等。
  • {n,m} (量词): 匹配前面的字符至少 n 次,但不超过 m 次。例如,a{2,4} 匹配 “aa”、”aaa” 或 “aaaa”。
  • | (管道符): 表示“或”的关系,匹配管道符前或后的表达式。例如,a|b 匹配 ‘a’ 或 ‘b’。
  • () (分组): 将表达式分组,可以捕获匹配的子字符串。
  • \d: 匹配任何数字字符 (0-9)。
  • \D: 匹配任何非数字字符。
  • \w: 匹配任何单词字符 (a-z, A-Z, 0-9, _)。
  • \W: 匹配任何非单词字符。
  • \s: 匹配任何空白字符 (空格、制表符、换行符等)。
  • \S: 匹配任何非空白字符。

3. RegexOptions 枚举

RegexOptions 枚举提供了一组标志,可以修改正则表达式引擎的行为。一些常用的选项包括:

  • IgnoreCase: 忽略大小写。
  • Multiline: 将 ^$ 分别匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。
  • Singleline: 使 . 匹配任何字符,包括换行符。
  • Compiled: 将正则表达式编译为可重用的程序集,提高匹配速度。
  • ExplicitCapture: 只捕获显式命名的组。

二、提取匹配项

提取匹配项是正则表达式最常用的功能之一。MatchMatchCollection 对象提供了访问匹配项信息的途径。

1. 使用 Match 对象提取单个匹配项

当使用 Regex.Match() 方法时,会返回一个 Match 对象。 该对象包含以下重要属性:

  • Success: 布尔值,指示是否找到了匹配项。
  • Value: 包含匹配的字符串。
  • Index: 匹配项在输入字符串中的起始位置。
  • Length: 匹配项的长度。
  • Groups: 包含捕获组的集合。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “Hello, my email is [email protected]. Contact me!”;
string pattern = @”\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*”; // 匹配电子邮件地址

    Match match = Regex.Match(input, pattern);

    if (match.Success)
    {
        Console.WriteLine("匹配成功!");
        Console.WriteLine("匹配的电子邮件地址: " + match.Value);
        Console.WriteLine("起始位置: " + match.Index);
        Console.WriteLine("长度: " + match.Length);
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

2. 使用 MatchCollection 对象提取多个匹配项

当需要提取所有匹配项时,可以使用 Regex.Matches() 方法,该方法返回一个 MatchCollection 对象。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “Hello, my email is [email protected]. Another email is [email protected]. Contact me!”;
string pattern = @”\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*”; // 匹配电子邮件地址

    MatchCollection matches = Regex.Matches(input, pattern);

    if (matches.Count > 0)
    {
        Console.WriteLine("找到 " + matches.Count + " 个电子邮件地址:");
        foreach (Match match in matches)
        {
            Console.WriteLine("  - " + match.Value);
        }
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

3. 提取捕获组

正则表达式中的括号 () 定义了捕获组。可以使用 Match.Groups 属性访问捕获组。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “My phone number is (123) 456-7890.”;
string pattern = @”((\d{3}))\s(\d{3})-(\d{4})”; // 匹配美国电话号码格式,并捕获区号、前缀和号码

    Match match = Regex.Match(input, pattern);

    if (match.Success)
    {
        Console.WriteLine("匹配成功!");
        Console.WriteLine("完整号码: " + match.Value);
        Console.WriteLine("区号: " + match.Groups[1].Value);
        Console.WriteLine("前缀: " + match.Groups[2].Value);
        Console.WriteLine("号码: " + match.Groups[3].Value);
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

三、按行显示匹配项

很多时候,我们需要处理多行文本,并按行显示匹配项。 这需要结合正则表达式的 Multiline 选项和字符串的行分割方法。

1. 使用 Multiline 选项

Multiline 选项使 ^$ 分别匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = @”Line 1: This line contains the word ‘example’.
Line 2: Another line with ‘example’ in it.
Line 3: No example here.
Line 4: The word ‘example’ appears again.”;

    string pattern = @"^.*example.*$"; // 匹配包含 "example" 的整行

    Regex regex = new Regex(pattern, RegexOptions.Multiline);
    MatchCollection matches = regex.Matches(input);

    if (matches.Count > 0)
    {
        Console.WriteLine("包含 'example' 的行:");
        foreach (Match match in matches)
        {
            Console.WriteLine("  - " + match.Value);
        }
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

2. 按行分割字符串并逐行匹配

另一种方法是将字符串按行分割成字符串数组,然后逐行应用正则表达式。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = @”Line 1: This line contains the word ‘example’.
Line 2: Another line with ‘example’ in it.
Line 3: No example here.
Line 4: The word ‘example’ appears again.”;

    string pattern = @"example"; // 匹配 "example"

    string[] lines = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);

    Console.WriteLine("包含 'example' 的行:");
    foreach (string line in lines)
    {
        if (Regex.IsMatch(line, pattern))
        {
            Console.WriteLine("  - " + line);
        }
    }
}

}
“`

四、高级用法和技巧

1. 命名捕获组

可以为捕获组命名,使其更易于理解和使用。 使用 (?<name>...) 语法来命名捕获组。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “My phone number is (123) 456-7890.”;
string pattern = @”((?\d{3}))\s(?\d{3})-(?\d{4})”;

    Match match = Regex.Match(input, pattern);

    if (match.Success)
    {
        Console.WriteLine("匹配成功!");
        Console.WriteLine("区号: " + match.Groups["AreaCode"].Value);
        Console.WriteLine("前缀: " + match.Groups["Prefix"].Value);
        Console.WriteLine("号码: " + match.Groups["Number"].Value);
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

2. 零宽度断言

零宽度断言允许在不消耗字符的情况下匹配字符串中的位置。常用的零宽度断言包括:

  • (?=...) (正向先行断言): 断言当前位置的后面必须匹配指定的模式。
  • (?!...) (负向先行断言): 断言当前位置的后面不能匹配指定的模式。
  • (?<=...) (正向后行断言): 断言当前位置的前面必须匹配指定的模式。
  • (?<!...) (负向后行断言): 断言当前位置的前面不能匹配指定的模式。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “The price is $100, but the discount is $20.”;
string pattern = @”(?<=\$)\d+”; // 匹配以 “$” 开头的数字

    MatchCollection matches = Regex.Matches(input, pattern);

    if (matches.Count > 0)
    {
        Console.WriteLine("价格:");
        foreach (Match match in matches)
        {
            Console.WriteLine("  - " + match.Value);
        }
    }
    else
    {
        Console.WriteLine("未找到匹配项!");
    }
}

}
“`

3. 使用 Regex.Replace 进行高级替换

Regex.Replace 方法不仅可以替换匹配的字符串,还可以使用 MatchEvaluator 委托进行更复杂的替换逻辑。

“`csharp
using System;
using System.Text.RegularExpressions;

public class Example
{
public static void Main(string[] args)
{
string input = “The temperature is 25C.”;
string pattern = @”(\d+)C”;

    string result = Regex.Replace(input, pattern, m =>
    {
        int celsius = int.Parse(m.Groups[1].Value);
        double fahrenheit = (celsius * 9.0 / 5.0) + 32;
        return fahrenheit.ToString("F2") + "F";
    });

    Console.WriteLine("转换后的字符串: " + result); // Output: The temperature is 77.00F.
}

}
“`

五、性能考虑

正则表达式的性能取决于多种因素,包括正则表达式的复杂性、输入字符串的大小以及使用的 RegexOptions

  • 避免过度复杂的正则表达式: 尽量简化正则表达式,减少回溯。
  • 使用 Compiled 选项: 对于需要多次使用的正则表达式,使用 Compiled 选项可以显著提高性能。
  • 避免在循环中创建 Regex 对象: 在循环外部创建 Regex 对象,并重用它。
  • 考虑使用字符串操作代替简单的正则表达式: 对于简单的字符串查找和替换,使用 string.Containsstring.Replace 等方法可能更有效率。

六、总结

C# 中的正则表达式提供了强大的文本处理能力。通过掌握 Regex 类的常用方法、正则表达式语法以及 RegexOptions,可以轻松地提取匹配项并按行显示。本文详细介绍了正则表达式的基础知识、提取匹配项的各种方法,并提供了丰富的示例代码和高级技巧,帮助读者在实际开发中灵活运用正则表达式,提高开发效率。记住,编写高效的正则表达式需要经验和不断的实践。希望本文能够帮助你更好地理解和使用 C# 中的正则表达式,从而解决各种文本处理问题。 不断尝试,不断学习,你将能够熟练掌握正则表达式的强大功能。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部