C# RegEx-重用子表达式

C# RegEx-重用子表达式,c#,.net,regex,C#,.net,Regex,假设我有一个与十六进制32位数字匹配的正则表达式: ([0-9a-fA-F]{1,8}) 当我构造一个正则表达式时,我需要多次匹配它,例如 (?<from>[0-9a-fA-F]{1,8})\s*:\s*(?<to>[0-9a-fA-F]{1,8}) (?[0-9a-fA-F]{1,8})\s*:\s*(?[0-9a-fA-F]{1,8}) 我是否每次都必须重复子表达式定义,或者是否有方法“命名并重用”它 我会想象(警告,虚构的语法!) (?{hexnum=[0-9

假设我有一个与十六进制32位数字匹配的正则表达式:

([0-9a-fA-F]{1,8})
当我构造一个正则表达式时,我需要多次匹配它,例如

(?<from>[0-9a-fA-F]{1,8})\s*:\s*(?<to>[0-9a-fA-F]{1,8})
(?[0-9a-fA-F]{1,8})\s*:\s*(?[0-9a-fA-F]{1,8})
我是否每次都必须重复子表达式定义,或者是否有方法“命名并重用”它

我会想象(警告,虚构的语法!)

(?{hexnum=[0-9a-fA-F]{1,8}})\s*:\s*(?{=hexnum})
其中,
hexnum=
将定义子表达式“hexnum,{=hexnum}将重用它


因为我已经学会了这一点:我正在使用.NET的
System.Text.RegularExpressions.Regex
,但一般的答案也会很有趣。

如果我正确理解了你的问题,你想重用某些模式来构建更大的模式吗

string f = @"fc\d+/";
string e = @"\d+";
Regex regexObj = new Regex(f+e);
除此之外,只有当您试图匹配之前在正则表达式中某个地方匹配的字符串时,使用才会有帮助

e、 g

将只匹配上面文本中的
文本
空格


这是一个示例文本,它不是标题,因为它不以2个空格结尾。

没有这样的预定义类。我认为您可以使用“忽略案例”选项简化它,例如:

(?i)(?<from>[0-9a-z]{1,8})\s*:\s*(?<to>[0-9a-z]{1,8})
(?[0-9a-z]{1,8})\s*:\s*(?[0-9a-z]{1,8})

为什么不做这样的事情,不是很短,而是更易于维护

String.Format("(?<from>{0})\s*:\s*(?<to>{0})", "[0-9a-zA-Z]{1,8}");
String.Format(“(?{0})\s*:\s*(?{0})”,“[0-9a-zA-Z]{1,8}”);

如果您想要更多的自文档代码,我会将数字regex字符串分配给一个正确命名的const变量

要重用正则表达式命名的捕获组,请使用以下语法:\k或\k'name'

所以答案是:

(?<from>[0-9a-fA-F]{1,8})\s*:\s*\k<from>
(?[0-9a-fA-F]{1,8})\s*:\s*\k
更多信息:

RegEx子例程 如果要多次使用子表达式而不重写它,可以将其分组,然后将其作为子例程调用。子例程可以通过名称、索引或相对位置调用

PCRE、Perl、Ruby、PHP、Delphi、R等都支持子例程。不幸的是,缺少.NET框架,但是可以使用一些.NET的PCRE库(例如)

语法 下面是子例程的工作方式:假设您有一个子表达式
[abc]
,希望在一行中重复三次

标准正则表达式
任何:
[abc][abc][abc]

子例程(按名称)
Perl:
(?'name'[abc])(?&name)(?&name)

PCRE:
(?P[abc])(?P>名称)(?P>名称)

Ruby:
(?[abc])\g\g

子例程,按索引 Perl/PCRE:
([abc])(?1)(?1)

Ruby:
([abc])\g\g

子例程,按相对位置 Perl:
([abc])(?-1)(?-1)

PCRE:
([abc])(?-1)(?-1)

Ruby:
([abc])\g\g

子例程,预定义的
这定义了一个子例程而不执行它。
Perl/PCRE:
(?(定义)(?'name'[abc])(?P>name)(?P>name)(?P>name)

例子 匹配有效的IPv4地址字符串,从0.0.0.0到255.255.255.255:
((?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9])\。(?:1)\。(?1)

无子例程:
((:25[0-0-5[0-0-0-5[0-0-5[0-0-5[0-0-5[0-0-9[0-9[0-9[0-9[0-9[0-9[0-5[0-5[0-5[0-5[0-5[0-5[0-5[0-5[0-5[0-0-5[0-0-0-5[0[0-5[0-0-5])))))),,((((((((((((((:::25:25:25[0-5[0-5[0-5[0-0-0-5[0-0-0-0-0-5[0-0-5[0-0-5[0-5[0-5[0-0-5[0-5[0-0-5[0-5[0-5[0-5[0-5[0-:[0-1]?[0-9]?[0-9]))

要解决最初发布的问题:
(?(?P[0-9a-fA-F]{1,8}))\s*:\s*(?(?P>hexnum))

更多信息

.NET正则表达式不支持模式递归,如果您可以在Ruby和PHP/PCRE中使用(其中,
hex
是一个名为捕获组的“技术”名称,其名称不应出现在主模式中),那么您可以在.NET中将块定义为单独的变量,然后使用它们来构建动态模式

从C#6开始,您可以使用插值字符串文字,它看起来非常像PCRE/Onigmo子模式递归,但实际上更干净,并且在组与“技术”捕获组同名时没有潜在的瓶颈:

:


正如中所建议的那样。

您应该使用在线工具及其保存的示例。我已经在使用了,谢谢你的建议:)\k匹配完全相同,而不是相同的模式。ssshhh。。。人们希望相信XML/HTML是不可解析的,因为他们不知道正则表达式可以做到这一点。
String.Format("(?<from>{0})\s*:\s*(?<to>{0})", "[0-9a-zA-Z]{1,8}");
(?<from>[0-9a-fA-F]{1,8})\s*:\s*\k<from>
using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
        var block = "[0-9a-fA-F]{1,8}";
        var pattern = $@"(?<from>{block})\s*:\s*(?<to>{block})";
        Console.WriteLine(Regex.IsMatch("12345678  :87654321", pattern));
    }
}
var pattern = string.Format(@"(?<from>{0})\s*:\s*(?<to>{0})", block);