c# 正则表达式基础知识

发布于:2025-03-19 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、使用原理

  1. 模式匹配机制
    • 在 C# 中,正则表达式通过定义一种模式来描述文本的特征。例如,\d表示匹配任意一个数字字符。当使用正则表达式进行匹配时,正则表达式引擎会从输入文本的起始位置开始,逐个字符地将输入文本与模式进行比较。
    • 引擎尝试找到一个连续的字符序列,该序列与整个模式完全匹配。如果找到了这样的序列,则匹配成功;否则,匹配失败。
  2. 回溯机制
    • 当正则表达式中存在可选部分(如a?表示a可选出现一次或不出现)或重复部分(如a+表示a出现一次或多次)时,可能会出现多种匹配的可能性。在这种情况下,正则表达式引擎会使用回溯机制。
    • 例如,对于模式a(b|c)+和输入文本abcc,引擎首先匹配a,然后遇到(b|c)+,它会尝试匹配b,接着匹配第一个c,然后再次匹配c。如果后续还有更多文本,并且匹配失败,引擎会回溯到上一个选择点,尝试其他可能的匹配路径,直到找到成功匹配或确定无法匹配为止。
  3. 捕获组
    • 捕获组是正则表达式中的一个重要概念,它允许你将匹配的一部分文本提取出来。通过将模式的一部分用圆括号()括起来,可以定义一个捕获组。
    • 例如,对于模式(\d{3})-(\d{3})-(\d{4})(用于匹配美国电话号码格式,如123 - 456 - 7890),有三个捕获组。在匹配成功后,可以通过Match.Groups属性访问这些捕获组,每个捕获组包含了相应部分的匹配文本。
  4. 编译与执行
    • 在 C# 中,当使用Regex类进行正则表达式操作时,Regex类会将正则表达式模式编译成一种内部表示形式,以便更高效地执行匹配操作。
    • 如果需要多次使用同一个正则表达式模式,可以使用Regex.CompileToAssembly方法将正则表达式编译成程序集,进一步提高性能。这在一些需要频繁进行正则匹配的场景(如文本处理的循环中)非常有用。

二、应用场景

  1. 数据验证
    • 邮箱地址验证:确保用户输入的邮箱地址符合正确的格式,例如user@domain.com。常见的正则表达式模式为^[a-zA-Z0 - 9_.+-]+@[a-zA-Z0 - 9 -]+\.[a-zA-Z0 - 9-.]+$
    • 电话号码验证:验证电话号码是否符合特定地区的格式。例如,美国电话号码可以用^\d{3}-\d{3}-\d{4}$来验证,其中^\d{3}表示以三个数字开头,-\d{3}表示中间是一个短横线和三个数字,-\d{4}$表示最后是一个短横线和四个数字。
  2. 文本提取
    • 从网页中提取链接:在处理网页内容时,需要提取其中的所有链接。可以使用类似https?://[^\s/$.?#].[^\s]*的正则表达式,它能匹配httphttps开头的链接。
    • 从日志文件中提取特定信息:例如,在日志文件中提取时间戳、错误代码等信息。假设日志格式为[2023 - 01 - 01 12:00:00] INFO - Message,可以用\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\]来提取时间戳部分。
  3. 文本替换
    • 格式化文本:将文本中的日期格式从MM/dd/yyyy替换为yyyy - MM - dd。可以使用正则表达式(\d{2})/(\d{2})/(\d{4})来匹配原日期格式,并通过替换操作将其转换为新的格式。
    • 屏蔽敏感信息:在处理用户数据时,可能需要屏蔽敏感信息,如电话号码中的部分数字。可以用(\d{3})\d{4}(\d{4})匹配电话号码,并将中间四位数字替换为****,得到类似123****5678的结果。
  4. 搜索过滤
    • 在文档中搜索特定模式:在大量的文档中搜索包含特定关键词或模式的段落。例如,在一篇技术文档中搜索所有包含TODO:标记的行,使用^TODO:.*的正则表达式,其中^TODO:表示以TODO:开头,.*表示任意字符(包括换行符)。
    • 筛选文件列表:在处理文件系统中的文件列表时,可以使用正则表达式来筛选符合特定命名模式的文件。例如,筛选出所有以report_开头,以.txt结尾的文件,可以用^report_.*\.txt$
  5. 词法分析
    • 编程语言解析:在编译器或解释器中,正则表达式用于将输入的代码分解成一个个词法单元(token)。例如,在解析 C# 代码时,使用正则表达式来识别关键字(如ifelse)、标识符(变量名、函数名)、运算符(如+-)等。
    • 标记语言解析:对于标记语言(如 HTML、XML),正则表达式可用于解析标签、属性等。例如,在解析 HTML 时,用<([a-zA-Z]+)(?:\s+[a-zA - Z0 - 9_-]+="[^"]*")*>来匹配标签及其属性。

三、常见正则符号含义

  1. 字符类
    • [abc]:匹配方括号内的任意一个字符,即abc。例如,[123]可以匹配123
    • [a - z]:匹配小写字母范围内的任意一个字符。例如,[a - f]可以匹配af之间的任意一个小写字母。
    • [^abc]:匹配除了方括号内字符之外的任意一个字符。例如,[^0 - 9]可以匹配除数字之外的任意字符。
  2. 预定义字符类
    • \d:匹配任意一个数字字符,等价于[0 - 9]。例如,\d{3}可以匹配三个连续的数字。
    • \D:匹配任意一个非数字字符,等价于[^0 - 9]
    • \w:匹配任意一个字母、数字或下划线字符,等价于[a - zA - Z0 - 9_]。例如,\w+可以匹配一个或多个由字母、数字或下划线组成的单词。
    • \W:匹配任意一个非字母、数字或下划线字符,等价于[^a - zA - Z0 - 9_]
    • \s:匹配任意一个空白字符(空格、制表符、换行符等),等价于[\f\n\r\t\v]。例如,\s+可以匹配一个或多个连续的空白字符。
    • \S:匹配任意一个非空白字符,等价于[^ \f\n\r\t\v]
  3. 限定符
    • *:匹配前面的元素零次或多次。例如,a*可以匹配空字符串、aaaaaa等。
    • +:匹配前面的元素一次或多次。例如,a+可以匹配aaaaaa等,但不能匹配空字符串。
    • ?:匹配前面的元素零次或一次。例如,a?可以匹配空字符串或a
    • {n}:匹配前面的元素恰好n次。例如,a{3}只能匹配aaa
    • {n,}:匹配前面的元素至少n次。例如,a{3,}可以匹配aaaaaaaaaaaa等。
    • {n,m}:匹配前面的元素至少n次,最多m次。例如,a{3,5}可以匹配aaaaaaaaaaaa
  4. 分组与捕获
    • (pattern):将pattern作为一个分组,用于捕获匹配的文本。例如,对于模式(\d{3})-(\d{3})-(\d{4})匹配电话号码123 - 456 - 7890,可以通过Match.Groups[1]获取第一个\d{3}匹配的123Match.Groups[2]获取456Match.Groups[3]获取7890
    • (?:pattern):将pattern作为一个非捕获分组。它用于分组但不捕获匹配的文本,这样可以避免在Match.Groups中产生额外的捕获组。例如,(?:a|b)+匹配ab的一次或多次出现,但不会在Match.Groups中创建捕获组。
  5. 边界匹配
    • ^:匹配字符串的开头。例如,^Hello可以匹配以Hello开头的字符串。
    • $:匹配字符串的结尾。例如,World$可以匹配以World结尾的字符串。
    • \b:匹配单词边界,即单词与非单词字符的边界。例如,\bHello\b可以匹配独立的Hello单词,而不会匹配HelloWorld中的Hello
    • \B:匹配非单词边界。例如,\BHello\B可以匹配HelloWorldHello部分(因为Hello前后都不是单词边界)。
  6. 转义字符
    • \:用于转义特殊字符,使它们失去特殊含义,仅表示其字面意思。例如,\.表示匹配一个点号,因为点号在正则表达式中有特殊含义(匹配任意字符)。同样,\*表示匹配一个星号。

四、详细案例代码

  1. 验证邮箱地址
using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string email = "test.user123@example - domain.com";
        string pattern = @"^[a-zA-Z0 - 9_.+-]+@[a-zA-Z0 - 9 -]+\.[a-zA-Z0 - 9-.]+$";
        bool isValid = Regex.IsMatch(email, pattern);
        Console.WriteLine($"Email {email} is valid: {isValid}");
    }
}

解释:

  • ^表示匹配字符串的开头。
  • [a-zA-Z0 - 9_.+-]+:匹配一个或多个字母、数字、下划线、点、加号或减号,这是邮箱用户名部分。
  • @:匹配邮箱地址中的@符号。
  • [a-zA-Z0 - 9 -]+:匹配域名部分,由字母、数字和短横线组成。
  • \.:转义后的点号,匹配实际的点号。
  • [a-zA-Z0 - 9-.]+:匹配顶级域名部分,由字母、数字、短横线和点号组成。
  • $:表示匹配字符串的结束。
  1. 提取 URL 链接
using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string text = "Check out these links: https://www.example.com, http://another - site.net, ftp://ftp.example.org";
        string pattern = @"https?://[^\s/$.?#].[^\s]*";
        MatchCollection matches = Regex.Matches(text, pattern);
        foreach (Match match in matches)
        {
            Console.WriteLine(match.Value);
        }
    }
}

解释:

  • https??表示?前面的s是可选的,即匹配httphttps
  • ://:匹配协议与域名之间的分隔符。
  • [^\s/$.?#]:匹配一个非空白字符且不是/$.?#的字符,这是域名的起始字符。
  • [^\s]*:匹配任意数量的非空白字符,用于匹配域名和路径部分。
  1. 替换文本中的电话号码
using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string text = "Contact me at 123 - 456 - 7890 or 555 - 123 - 4567";
        string pattern = @"\d{3}-\d{3}-\d{4}";
        string replacement = "(***)-***-****";
        string newText = Regex.Replace(text, pattern, replacement);
        Console.WriteLine(newText);
    }
}

解释:

  • \d{3}:匹配三个连续的数字。
  • -\d{3}:匹配一个短横线和三个连续的数字。
  • -\d{4}:匹配一个短横线和四个连续的数字。
  • Regex.Replace方法将匹配到的电话号码格式替换为(***)-***-****
  1. 搜索日志文件中的错误信息
using System;
using System.IO;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string logFile = "app.log";
        string pattern = @"ERROR:\s.*";
        try
        {
            string[] lines = File.ReadAllLines(logFile);
            foreach (string line in lines)
            {
                if (Regex.IsMatch(line, pattern))
                {
                    Console.WriteLine(line);
                }
            }
        }
        catch (IOException e)
        {
            Console.WriteLine($"Error reading file: {e.Message}");
        }
    }
}

解释:

  • ERROR::匹配ERROR:字符串。
  • \s:匹配一个空白字符(通常是空格)。
  • .*:匹配任意字符(包括换行符)零次或多次,用于匹配错误信息的具体内容。
  1. 提取 HTML 标签内的文本
using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string html = "<p>Hello, World!</p><div>Some content</div><span>Another text</span>";
        string pattern = @">(.*?)<";
        MatchCollection matches = Regex.Matches(html, pattern);
        foreach (Match match in matches)
        {
            Console.WriteLine(match.Groups[1].Value);
        }
    }
}

解释:

  • >:匹配 HTML 标签的结束符号。
  • (.*?):这是一个非贪婪捕获组。.*表示匹配任意字符零次或多次,?表示非贪婪模式,即尽可能少地匹配字符,以找到第一个><之间的内容。
  • <:匹配 HTML 标签的开始符号。
  • 通过Match.Groups[1].Value获取捕获组中匹配的文本,即 HTML 标签内的文本内容。

网站公告

今日签到

点亮在社区的每一天
去签到