C#(104):正则表达式Regex


参考资料:

  • 在 Visual Studio 中使用正则表达式
    in-visual-studio?view=vs-2019>

  • 正则表达式语言 - 快速参考
    [https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-
    expression-language-quick-reference ](https://docs.microsoft.com/zh-
    cn/dotnet/standard/base-types/regular-expression-language-quick-reference )

一、正则表达式应用举例

1、C#校验合法性:

    if (!Regex.IsMatch(this.txtCode.Text.Trim(), @"^[0-9]*$", RegexOptions.Singleline))
        Console.Write("只能输入数字");

2、C#限制输入

输入除了数字之外的所有非法字符的判断

    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        //退格键(8)、 回车(13)、全选(1)、复制(3)、粘贴(22)
        e.Handled = !(Regex.IsMatch(e.KeyChar, @"\d", RegexOptions.Singleline) || e.KeyChar == (char)8 || e.KeyChar != (char)13);
    }

粘贴时过滤不是数字的字符

    private void textbox1_TextChanged(object sender, EventArgs e)
     {
      var reg = new Regex("^[0-9]*$");
      var str = textbox1.Text.Trim();
      var sb = new StringBuilder();
      if (!reg.IsMatch(str))
      {
        for (int i = 0; i < str.Length; i++)
        {
          if (reg.IsMatch(str[i].ToString()))
          {
            sb.Append(str[i].ToString());
          }
        }
        textbox1.Text = sb.ToString();
        //定义输入焦点在最后一个字符
         textbox1.SelectionStart = textbox1.Text.Length;
      }
     }

3、 正则表达式 匹配 闭合 HTML 标签(支持 嵌套 )

1、分组构造

分组构造描述了正则表达式的子表达式,通常用于捕获输入字符串的子字符串。 分组构造包括下表中列出的语言元素。 有关详细信息,请参阅
[分组构造](https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/grouping-
constructs-in-regular-expressions)。

分组构造 描述 模式 匹配
( subexpression ) 捕获匹配的子表达式并将其分配到一个从 1 开始的序号中。 (\w)\1 "deep" 中的
"ee"
(?< name > subexpression ) 将匹配的子表达式捕获到一个命名组中。
(?\w)\k "deep" 中的 "ee"
(?< name1 - name2 > subexpression ) 定义平衡组定义。 有关详细信息,请参阅
[分组构造](https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/grouping-
constructs-in-regular-expressions)中的"平衡组定义"部分。
(((?'Open'\()[^\(\)]*)+((?'Close-Open'\))[^\(\)]*)+)*(?(Open)(?!))$
"3+2^((1-3)*(3-1))" 中的 "((1-3)*(3-1))"
(?: subexpression ) 定义非捕获组。 Write(?:Line)? "Console.WriteLine()"
中的 "WriteLine" "Console.Write(value)" 中的 "Write"
(?imnsx-imnsx: subexpression ) 应用或禁用 子表达式 中指定的选项。 有关详细信息,请参阅
[正则表达式选项](https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-
expression-options)。 A\d{2}(?i:\w+)\b "A12xl A12XL a12xl" 中的 "A12xl"
"A12XL"
(?= subexpression ) 零宽度正预测先行断言。 \w+(?=\.) `"He is. The dog ran.
The sun is out."中的"is""ran""out"`
(?! subexpression ) 零宽度负预测先行断言。 \b(?!un)\w+\b `"unsure sure unity
used"中的"sure""used"`
(?<= subexpression ) 零宽度正回顾后发断言。 (?<=19)\d{2}\b `"1851 1999 1950
1905 2003"中的"99""50""05"`
(? subexpression ) 零宽度负回顾后发断言。 (? `"1851 1999 1950
1905 2003"中的"51""03"`
(?> subexpression ) 原子组。 [13579](?>A+B+) "1ABB 3ABBC 5AB 5AC" 中的
"1ABB""3ABB""5AB"

2、举例:

1、匹配带有Class的div标签:

<(?i)div[>]*(?i)class=["']?.+["']?[\s\S]*>[<>](((?'Open'<(?i)div[>]*>)[<>])+((?'-Open')[^<>])+)(?(Open)(?!))

文本:

    
CSHTML 复制

2、匹配class以successful开头的的div

<(?i)div[>]*(?i)class=["']?successful.+["']?[\s\S]*>[<>](((?'Open'<(?i)div[>]*>)[<>])+((?'-Open')[^<>])+)(?(Open)(?!))

3、匹配所有span标签

<(?i)span[>]*>[<>](((?'Open'<(?i)span[>]*>)[<>])+((?'-Open')[^<>])+)(?(Open)(?!))

二、.Net正则表达式测试器

网页版本:https://deerchao.cn/tools/wegester/

下载版:https://deerchao.cn/tools/regester/

1、功能简介

  • 自动加载上次关闭前运行的最后一组数据
  • 支持树形,表格, 文本等三种结果查看方式
  • 支持快捷键操作(F5运行, F4切换查询替换模式, F6切换结果显示方式, F2复制代码, Ctrl+Tab切换焦点)
  • 选中树结点或单元格时自动选中源文本中对应的部分
  • 表格内容可自由选择, 自由复制
  • 表格内容可导出为csv/xlsx文件
  • 支持拖入文件作为匹配源文本
  • 支持忽略大小写,单行模式,多行模式,忽略空白,显式匹配, ECMAScript等各种选项
  • 可解析类似new Regex("abc", RegexOptions.Singleline | RegexOptions.Multiline)格式的C#代码
  • 支持生成并拷贝C#代码到系统剪切板

2、下载与安装

你可以使用以下两种方式中的任意一个来下载安装正则表达式测试器.

安装版: 下载
Regester安装程序,解压后运行
RegesterSetup.zh.exe

绿色版: 下载 Regester,解压后运行
Regester.exe,如果无法启动,请自行下载安装 Microsoft .Net Framework
4.5 后再试

3、界面截图

三、.NET正则表达式Regex

在C#中,要使用正则表达式类,请在源文件开头处添加以下语句:

    using System.Text.RegularExpressions;

可参考微软文档 :[.NET 正则表达式](https://docs.microsoft.com/zh-cn/dotnet/standard/base-
types/regular-expression-language-quick-reference?redirectedfrom=MSDN
"https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-
expressions")

1、IsMatch(Input,patter[,options]) 否则匹配

如果表达式在字符串中匹配,返回布尔值。

    if (Regex.IsMatch("a.b.c.d", @"(\w)\.(\w)", RegexOptions.IgnoreCase))
        Console.Write("匹配成功");

1、正则表达式选项:RegexOptions

有如下选项

RegexOptions枚举值

内联标志

简单说明

---|---|---

ExplicitCapture

n

只有定义了命名或编号的组才捕获

IgnoreCase

i

不区分大小写

IgnorePatternWhitespace

x

消除模式中的非转义空白并启用由 # 标记的注释。

MultiLine

m

多行模式,其原理是修改了^和$的含义

SingleLine

s

单行模式,和MultiLine相对应

2、内联标志

相对于用RegexOptions在new
Regex时定义Regex表达式的全局选项来说,内联标志可以更小粒度(以组为单位)的定义匹配选项,从而更方便表达我们的思想。

\bA(?i)b\w+\b 匹配“ABA Able Act”中的“ABA”和“Able”

2、Match(Input,patter[,options]) 单个匹配

如果在输入字符串中发现匹配,则返回匹配对象。(返回单个匹配对象)

    Match m = Regex.Match("a.b.c.d", @"(\w)\.(\w)");
    if (m.Success)
        Console.Write("Match=" + m.Value + " pos:" + m.Index);
    
    
    //Match=a.b pos:0

3、Matches(Input,patter[,options]) 多个匹配

如果在输入字符串中发现全部匹配,则返回匹配集合对象。(返回多个匹配对象)

注意:匹配是不能重叠的,如果有重叠,在默认情况下,就选择最长的匹配(除非元字符后加问号)。

Regex的Match()或Matches()=>Match匹配(MatchCollection)=>Group
组(GroupCollection子模式)=>Capture捕获(CaptureCollection)

    MatchCollection mc = Regex.Matches("a.b.c.d", @"(\w)\.(\w)");
    for (int i = 0; i < mc.Count; i++)
    {
        Match match = mc[i];
        Console.WriteLine("Match=" + match.Value + " :" + i);
    
        for (int j = 0; j < match.Groups.Count; j++)
        {
            Group group = match.Groups[j];
            Console.WriteLine("--Group =" + group.Value + " :" + j);
            for (int k = 0; k < group.Captures.Count; k++)
            {
                Console.WriteLine("------Captures =" + group.Captures[k].Value + " :" + k);
            }
        }
    }

结果如下:

Match=a.b :0
----Group =a.b :0
--------Captures =a.b :0
----Group =a :1
--------Captures =a :0
----Group =b :2
--------Captures =b :0
Match=c.d :1
----Group =c.d :0
--------Captures =c.d :0
----Group =c :1
--------Captures =c :0
----Group =d :2
--------Captures =d :0

返回匹配成功后的第一个子模式的值:

    var mc = Regex.Matches(Server.UrlDecode(client.ResponseHeaders["Content-Disposition"]), @"filename=(.+)");
    string filename = mc[0].Groups[1].Value;

4、Replace(Input,patter,replacement或evaluator [,options]) 替换

用给定的Replacement替换input中的匹配。

    Console.WriteLine(Regex.Replace("this test*", "[^a-zA-Z]", "()")); //this()test()
    Console.WriteLine(Regex.Replace("sevenyear", @"\w+", m =>
    {
        return m.Value.ToUpper();
    })
    ); //SEVENYEAR

5、Split(Input,patter[,options]) 拆分

在由模式定义的位置拆分input,返回string[]

    string[] s = Regex.Split("first-second-thrid", "-");
    for (int i = 0; i < s.Length; i++)
    {
        Console.WriteLine(s[i]);
    }  
    //first
    
    
    //second  
    //thrid

拆分字符串举例:等长度分割字符串

1、每4个长度进行分割

    var temp = Regex.Split("1234abcdef", @"(?<=\G.{4})(?!$)");
    temp.ToList().ForEach(t => Console.WriteLine(t));  
    //1234  
    //abcd  
    //ef

2、提取单词

    var temp = Regex.Split("1234 abcd efa", @"(?<=\S+\b\s+)");
    temp.ToList().ForEach(t => Console.WriteLine(t));  
    //1234  
    //abcd  
    //ef

3、每两个单词进行分割

    var temp = Regex.Split("1234,abcd,12345,abcd,ab", @"(?<=\G(?:\w+[,,]){2})");
    temp.ToList().ForEach(t => Console.WriteLine(t));  
    //1234,abcd,  
    //12345,abcd,  
    //ab

6、实例化Regex类

    Regex exp= new Regex(@"\w\.\w", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
    MatchCollection mc = exp.Matches("a.b.c.d");

实例:

    void Main()
    {
        string ss = "259年又62天";
        MatchCollection mc = Regex.Matches(ss, @"(?:(?\d+)年)?又?(?:(?\d+)天)?");
        for (int i = 0; i < mc.Count; i++)
        {
            Match match = mc[i];
            Console.WriteLine("Match[" + i + "],Value:" + match.Value);
    
            for (int j = 0; j < match.Groups.Count; j++)
            {
                Group group = match.Groups[j];
                Console.WriteLine("--Group[" + j + "],Name:" + group.Name + "  ,Value:" + group.Value);
                for (int k = 0; k < group.Captures.Count; k++)
                {
                    Console.WriteLine("------Captures[" + k + "],Value:" + group.Captures[k].Value);
                }
            }
            Console.WriteLine();
        }
    }

Match[0],Value:259年又62天
--Group[0],Name:0 ,Value:259年又62天
------Captures[0],Value:259年又62天
--Group[1],Name:year ,Value:259
------Captures[0],Value:259
--Group[2],Name:month ,Value:62
------Captures[0],Value:62

Match[1],Value:
--Group[0],Name:0 ,Value:
------Captures[0],Value:
--Group[1],Name:year ,Value:
--Group[2],Name:month ,Value:

相关