在命名捕获中获取表达式

时间:2017-04-10 20:18:55

标签: c# regex

我提供了一个文本框,用于输入正则表达式以匹配文件名。我计划使用Regex方法GetGroupNames()检测它们提供的任何命名捕获组。

我想获得他们在每个命名捕获组中输入的表达式。

例如,他们可能会输入这样的正则表达式:

December (?<FileYear>\d{4}) Records\.xlsx

除了手动解析正则表达式字符串之外,是否有方法或手段来获取子表达式\d{4}

3 个答案:

答案 0 :(得分:1)

这是一个丑陋的强力扩展,用于解析而不使用另一个正则表达式来检测子表达式(或子模式):

    public static string GetSubExpression(this Regex pRegex, string pCaptureName)
    {
        string sRegex = pRegex.ToString();
        string sGroupText = @"(?<" + pCaptureName + ">";
        int iStartSearchAt = sRegex.IndexOf(sGroupText) + sGroupText.Length;
        string sRemainder = sRegex.Substring(iStartSearchAt);
        string sThis;
        string sPrev = "";
        int iOpenParenCount = 0;
        int iEnd = 0;
        for (int i = 0; i < sRemainder.Length; i++)
        {
            sThis = sRemainder.Substring(i, 1);
            if (sThis == ")" && sPrev != @"\" && iOpenParenCount == 0)
            {
                iEnd = i;
                break;
            }
            else if (sThis == ")" && sPrev != @"\")
            {
                iOpenParenCount--;
            }
            else if (sThis == "(" && sPrev != @"\")
            {
                iOpenParenCount++;
            }
            sPrev = sThis;
        }
        return sRemainder.Substring(0, iEnd);
    }

用法如下:

    Regex reFromUser = new Regex(txtFromUser.Text);
    string[] asGroupNames = reFromUser.GetGroupNames();
    int iItsInt;
    foreach (string sGroupName in asGroupNames)
    {
        if (!Int32.TryParse(sGroupName, out iItsInt)) //don't want numbered groups
        {
            string sSubExpression = reParts.GetSubExpression(sGroupName);
            //Do what I need to do with the sub-expression
        }
    }

现在,如果您想生成测试或样本数据,可以使用名为&#34; Fare&#34;的NuGet包。获得子表达式后,按以下方式:

            //Generate test data for it
            Fare.Xeger X = new Fare.Xeger(sSubExpression);
            string sSample = X.Generate();

答案 1 :(得分:0)

这是一个使用正则表达式匹配正则表达式中的捕获组的解决方案。想法来自这篇文章Using RegEx to balance match parenthesis

\(\?\<(?<MyGroupName>\w+)\>
(?<MyExpression>
((?<BR>\()|(?<-BR>\))|[^()]*)+
)
\)

或更简洁......

\(\?\<(?<MyGroupName>\w+)\>(?<MyExpression>((?<BR>\()|(?<-BR>\))|[^()]*)+)\)

并使用它可能如下所示:

string sGetCaptures = @"\(\?\<(?<MyGroupName>\w+)\>(?<MyExpression>((?<BR>\()|(?<-BR>\))|[^()]*)+)\)";
MatchCollection MC = Regex.Matches(txtFromUser.Text, sGetCaptures );
foreach (Match M in MC)
{
    string sGroupName = M.Groups["MyGroupName"].Value;
    string sSubExpression = M.Groups["MyExpression"].Value;
    //Do what I need to do with the sub-expression
    MessageBox.Show(sGroupName + ":" + sSubExpression);
}

对于原始问题中的示例,消息框将返回FileYear:\d{4}

答案 2 :(得分:0)

此模式(?<=\(\?<\w+\>)([^)]+)将为您提供所有已命名的匹配捕获表达式以及捕获的名称。它使用负面外观来确保匹配的文本在它之前有(?<...>

string data = @"December (?<FileYear>\d{4}) Records\.xlsx";
string pattern = @"(?<=\(\?<\w+\>)([^)]+)";

Regex.Matches(data, pattern)
     .OfType<Match>()
     .Select(mt => mt.Groups[0].Value)

返回

的一项

\d{4}

虽然(?<FileMonth>[^\s]+)\s+(?<FileYear>\d{4}) Records\.xlsx等数据会返回两个匹配项:

[^\s]+

\d{4}