首页 > 解决方案 > 正则表达式 - 查找与模式不匹配的组

问题描述

我对正则表达式很陌生,我正在尝试验证文件路径以查看它是否与我的正则表达式模式匹配,这表示文件路径的正确形式。

这是正则表达式模式:

string expression = (^P:)\\([A-Z]{3})\\(\d{6})\\(Revit)\\(Model)

我在我的 C# 程序中简单地匹配它

Match match = Regex.Match(toCheck, expression);

现在这适用于正确的文件夹路径,例如P:\SYD\121174\Revit\Model

但是,如果我输入一个几乎正确的路径,例如P:\SYD\121174\ Rhino \Model(粗体不同)我希望从match对象中得到哪个组是错误的,所以我可以将它报告给用户。
我试过这样的事情:

            foreach (Group group in match.Groups)
            {
                if (!group.Success)
                {
                    failingGroup = group.Index;
                }
            }

但后来我明白,如果字符串不匹配,那么我不会得到任何组。

有没有办法让哪个组不匹配?

标签: c#regex

解决方案


您的正则表达式将变得超长:

(?:(^P:)|[^\\]+)\\(?:([A-Z]{3})|[^\\]+)\\(?:(\d{6})|[^\\]+)\\(?:(Revit)|[^\\]+)\\(?:(Model)|[^\\]+)

这是一个更美化的版本:

(?:(^P:)|[^\\]+)\\
(?:([A-Z]{3})|[^\\]+)\\
(?:(\d{6})|[^\\]+)\\
(?:(Revit)|[^\\]+)\\
(?:(Model)|[^\\]+)

本质上,对于每个组,我添加了一个替代 match [^\\]+。这将匹配除斜线之外的任何其他内容。因此,如果路径表示Revi而不是Revit,则第 4 组 ( (Revit)) 将不匹配,但不在组 ( [^\\]+) 中的第二个替代方案将匹配。现在,即使一个组失败,正则表达式仍然会匹配,并且您必须检查每个组Success以了解路径是否是您想要的路径:

var failedGroups = match.Groups.Cast<Group>().Where(x => !x.Success).ToList();
var success = !failedGroups.Any();

我个人不喜欢这么长的正则表达式,我会使用这样的超级宽松正则表达式:

^([^\\]+)(?:\\([^\\]+)){4}

并依次检查每个组并捕获:

if (match.Groups[1].Value != "P:") {
    // Group 1 in your original regex is wrong!
}
if (!Regex.IsMatch(match.Groups[2].Captures[0].Value, "^[A-Z]{3}$")) {
    // Group 2 in your original regex is wrong
}
if (!Regex.IsMatch(match.Groups[2].Captures[1].Value, @"^\d{3}$")) {
    // Group 3 in your original regex is wrong
}
if (match.Groups[2].Captures[2].Value != "Revit") {
    // Group 4 in your original regex is wrong
}
if (match.Groups[2].Captures[3].Value != "Model") {
    // Group 5 in your original regex is wrong
}

编辑:您似乎希望允许路径少于 5 个组件。您可以将{4}量词设为 a {0,4}(现在更加宽松),并检查第 2 组是否有 4 个捕获:

^([^\\]+)(?:\\([^\\]+)){0,4}
if (match.Groups[2].Captures.Count == 4) {
    if (match.Groups[1].Value != "P:") {
        // Group 1 in your original regex is wrong!
    }
    if (!Regex.IsMatch(match.Groups[2].Captures[0].Value, "^[A-Z]{3}$")) {
        // Group 2 in your original regex is wrong
    }
    if (!Regex.IsMatch(match.Groups[2].Captures[1].Value, @"^\d{3}$")) {
        // Group 3 in your original regex is wrong
    }
    if (match.Groups[2].Captures[2].Value != "Revit") {
        // Group 4 in your original regex is wrong
    }
    if (match.Groups[2].Captures[3].Value != "Model") {
        // Group 5 in your original regex is wrong
    }
} else {
    // the path is shorter than expected
}

推荐阅读