C# c“嵌套量词-多个”&引用;在模式中

C# c“嵌套量词-多个”&引用;在模式中,c#,regex,C#,Regex,我试图查找目录中是否至少有一个文件与模式匹配(仅使用“?”和“*”通配符),但某些组合会不断抛出嵌套限定符错误。例如-TestCashFile\u 10\u 12-25-2016?????.c???不起作用 这些模式来自非技术用户(他们接受过这两个通配符的基本用法方面的教育),因此“?”和“*”可以在文件名中的几乎任何地方出现,我没有太多的控制权 这些模式有什么问题 这是运行此正则表达式的C#代码段- string fileName = C:\TestFiles\TestCashFile_10_

我试图查找目录中是否至少有一个文件与模式匹配(仅使用“?”和“*”通配符),但某些组合会不断抛出嵌套限定符错误。例如-
TestCashFile\u 10\u 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);

更新-问题已经解决,但如果它有助于其他人寻找类似的东西,请澄清-在本例中,我希望“?”表示必须只有一个元素(与零或一个元素相反)

操作符指定上一个元素可以出现0次或1次

??与上一个元素零次或一次匹配。“rai?n”“ran”“rain”

如果您像@Ed Plunkett所说的那样使用内置于
Directory.GetFiles
中的通配符,那么它的工作原理应该与您正在寻找的类似

如果您仍然希望对RegEx使用当前方法,请执行以下操作:

  • *
    -任意数量的字符
  • {n}
    -将
    n
    替换为预期的字符数
  • {m,n}
    -将
    m
    替换为预期的最小字符数,将n替换为预期的最大字符数
如果您需要“?”精确匹配任意字符中的两个,那么您是对的,您必须使用正则表达式。文件系统通配符将“?”视为“零或任意字符之一”

但您不能按您尝试的方式来做,因为您要求用户提供文件系统通配符--您只是稍微改变了语义。您必须将用户的字符串转换为所需的正则表达式:

a???.*
必须成为

a.?.?.?\..*
  • 每个问号变成“.”:正好是任何字符中的一个
  • 每个“.”变为“.”,因为unescaped“.”是正则表达式中的特殊字符
  • 每个“”都必须变为“”:任何字符的零个或多个(猜测此字符)
文件
字符串和
的.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提供了一种更好、更干净的方法来做同样的事情:

var reStr = Regex.Escape(someWildcardThing).Replace(@"\?", ".").Replace(@"\*", ".*")

我自己没有理由不这样做,除了在这么多年后仍然是一名恢复中的C程序员

看。。有什么我遗漏的吗?您似乎在使用文件系统通配符,就好像它们是正则表达式一样。他们不是。这不可能。文件通配符和正则表达式不是一回事。不管怎样,@EdPlunkett说的话在你尝试重新发明轮子之前应该仔细考虑。@EdPlunkett,@spender我刚刚试过
Directory.GetFiles(Directory,file)
,它似乎更像
C:\TestFiles\TestCashFile\u 10\u 12-25-2016*.C*
@EdPlunkett我只是试过你建议的方法,但根本不起作用。TestCashFile_10_12-25-2016.c??根据您的建议返回文件“TestCashFile_10_12-25-2016.csv”、“TestCashFile_10_12-25-2016_B.csv”等。谢谢。我的错误是,我曾设想,
将确保每个
都必须有一个元素。我只是尝试将其更改为TestCashFile_10_12-25-2016{2}.c{2},但它也不会返回任何结果。文件夹中存在名为“TestCashFile\u 10\u 12-25-2016\u D.csv”和“TestCashFile\u 10\u 12-25-2016\u D.csv”等的文件。您需要
(句点/点),它指示本例中的任何字符。因此,请尝试
TestCashFile\u10\u12-25-2016.{2}\\\.c.{2}
。您还需要在文件扩展名的
上添加转义斜杠,以将其视为实际字符,尽管这会带来问题,因为您已经在\\上拆分了…谢谢。这很有效。嵌套的量词异常似乎也已通过此更改自行解决。这是一个System.ArgumentException,带有消息“嵌套的量词…”,我在问题中的模式是在Regex.Match上抛出的。这似乎是关于stackoverflow的一个非常常见的问题,但我无法为我的具体案例找到解决方案。很高兴知道修复正则表达式也解决了这个问题。哦,好吧,我明白了:根据正则表达式语法规则,“a?*”是一个异想天开的请求:“零或多个零或一个a”。所以不管出于什么原因,他们提出了一个例外。现在,通过字符串操作将通配符转换为属性regex,这是不可能发生的。“a?*”变为“a…”,这是合法的。这也提醒了我——我需要对translate函数做更多的修改。@Achiles我刚刚添加了一个更新版本的
TranslateWildcardsToRegex()
。它解决了一些可能会打破旧字符的特殊字符。@EdPlunkett我不由得感到,使用
Regex.Escape
,这一点可以显著改进。难道不能用像
Regex.Escape(someWildcardThing.Replace(@“\?”,“)。Replace(@“\*”,“*”)
这样简单的东西来完成吗?
var reStr = Regex.Escape(someWildcardThing).Replace(@"\?", ".").Replace(@"\*", ".*")