c#嵌套量词 - 多个“?”在模式中

时间:2017-01-10 16:42:39

标签: c# regex

我试图查找目录中是否至少有一个文件匹配模式(仅使用“?”和“*”通配符),但某些组合会继续抛出嵌套限定符错误。例如 - TestCashFile_10_12-25-2016????????.c??不起作用。

模式来自非技术用户(他们受过这两个通配符的基本用法教育)所以“?”并且“*”可以在文件名中的任何位置进行,我没有太多控制权。

这些模式有什么问题?

这是运行此正则表达式的C#代码段 -

string fileName = C:\TestFiles\TestCashFile_10_12-25-2016????????.c??'
string directory = Path.GetDirectoryName(fileName);
string[] temp = fileName.Split('\\');
string file = temp[temp.Length - 1];
var found = Directory.GetFiles(directory).Any(p => Regex.Match(p, file).Success);

更新 - 这个问题已经解决,但是如果它帮助其他人寻找类似的东西,只是为了澄清 - 在这种情况下,我想要“?”意味着必须只有一个元素(而不是零或一个元素)。

2 个答案:

答案 0 :(得分:1)

?运算符指定前一个元素可以出现0或1次。

https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx

  

?匹配前一个元素零次或一次。 " RAI N'#34?; "跑","下雨"

如果您使用Directory.GetFiles内置的通配符,如@Ed Plunkett所说,它应该与您要查找的内容类似。

如果您仍想在RegEx中使用当前方法,请执行以下操作:

  • .* - 任意数量的字符
  • .{n} - 将n替换为预期字符数
  • .{m,n} - 将m替换为最小预期字符数,将n替换为最大预期字符数。

答案 1 :(得分:1)

如果你需要“??”要匹配任何一个字符中的两个然后你是对的,你将不得不使用正则表达式。文件系统通配符对待“?”作为“零或任何一个角色”。

但是你不能按照你想要的方式去做,因为你要求你的用户使用文件系统通配符 - 你只是稍微改变了语义。你必须将用户的字符串转换为你想要的正则表达式:

int startIndex = 0;

for (int i = 0; i < 10; i++)
{
    foreach (DataRow rows in selectedDataRow.Skip(startIndex).Take(20))
    {
        smsRecordId += rows["activityid"].ToString() + ",";
        smsSubject = rows["subject"].ToString();
        mobileNum += rows["telephone1"].ToString() + ",";
    }

    startIndex += 20;
}

必须成为

a???.*
  • 每个问号都变成“。”:完全是任何一个字符。
  • 每个“。”变成“。”,因为未转义为“。”是正则表达式中的特殊字符。
  • 每个“”必须变成“。”:任何角色零或更多(猜测这个角色)。

a.?.?.?\..* 字符串执行此操作,file应该有效。

如果事情在运行时变得有点慢,你可能想要编译正则表达式:

.Any(p => Regex.Match(p, file).Success);

我认为这适用于file = TranslateWildcardsToRegex(file); var re = new Regex(file); var found = Directory.GetFiles("").Any(p => re.IsMatch(p));

TranslateWildcardsToRegex()

<强>更新

在评论中@spender提供了一种更好,更清晰的方法来做同样的事情:

public static String TranslateWildcardsToRegex(String s)
{
    StringBuilder sb = new StringBuilder();

    foreach (var ch in s)
    {
        switch (ch)
        {
            case '?':
                sb.Append(".");
                break;

            case '*':
                sb.Append(".*");
                break;

            //  Escape a variety of characters that 
            //  mean something special in a regex
            case '(':
            case ')':
            case '{':
            case '}':
            case '[':
            case ']':
            case '.':
                sb.Append("\\" + ch);
                break;

            default:
                sb.Append(ch);
                break;
        }
    }

    return sb.ToString();
}

在这些年之后,除了仍然是一名正在恢复的C程序员之外,我没有任何理由不这样做。