2014-10-17 90 views
0

我的C#.NET程序使用:正则表达式来验证文件搜索模式

DirInfo.EnumerateFiles(Program.sSourceFilePattern, SearchOption.TopDirectoryOnly) 

搜索文件夹匹配“sSourceFilePattern”文件名。此搜索模式是用户提供的,我希望在执行DirInfo之前验证模式。

我发现了一个正则表达式模式在How do I check if a given string is a legal/valid file name under Windows?,我抬起和修改,以允许通配符*和?:

sPattern = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\:\"";|/]+$"; 

这种模式运作得相当好,但仍然会允许涉及多个通配符无意义的模式。例如,这将允许像无效的搜索字符串:

abc*123.txt 
abc*???.txt 
*abc.txt 

我认为,完善这一进一步将涉及超过regexs更多,因为它需要运用逻辑在哪里可能会出现星号,什么可以跟着走,无论是前之后(分隔符)等

不过,我将不胜感激任何建议,以改善这种正则表达式来捕捉更多的常见错误。提前致谢!

+2

为什么你的例子是无效的搜索字符串? 1和3是有意义的,2可以简化为'abc * .txt',但从我看到它的位置仍然有效。 – 2014-10-17 12:50:19

+3

究竟是什么使一个无效的搜索字符串,在你的情况?它是应用程序可能无法搜索的目录吗? – Nzall 2014-10-17 12:55:14

+0

感谢您的意见和您的观点都很好。我的目标是验证搜索字符串的语法正确性,而不是仅仅验证那些不会轰炸程序的字符串。幸运的是,Windows命令提示符和DirInfo.EnumerateFiles都非常宽容。如果提供了无效的搜索模式,他们只是不会返回任何匹配。 – KMorley 2014-10-17 19:54:26

回答

0

我决定星号通配符规则对于我可以设计的任何正则表达式来说太复杂了,并且决定用逻辑处理它。事实证明,这比我原先预计的要简单:

if (bResult = Regex.IsMatch(sResult, sPattern, RegexOptions.CultureInvariant)) 
{ 
    // Reuse bResult and preset to false. Only passing all tests sets to true: 
    bResult = false; 

    // True - no reserved words or illegal characters, so test further. 
    // Check wild card placement. '?' may appear anywhere, but '*' follows specific rules. 
    // Use LINQ to count occurences of asterisk. Zero to two is acceptable: 
    iCount = sResult.Count(f => f == '*'); 

    if (iCount == 0) 
    { 
     // No asterisks, so search pattern testing is finished and the pattern is good. 
     bResult = true; 
    } 
    else if (iCount == 1) 
    { 
     // One asterisk, so test further. If one asterisk, it must be last character in string: 
     if (sResult.Length == sResult.IndexOf("*")+1) 
     { 
      // One asterisk and it IS the last character. 
      bResult = true; 
     } 
    } 
    else if (iCount == 2) 
    { 
     // Two asterisks, so test further. The first asterisk can ONLY be followed 
     // by period. The second asterisk must be the last character in the string: 
     iIdx = sResult.IndexOf("*"); 
     if (sResult.Substring(iIdx+1,1) == ".") 
     { 
      // First asterisk is followed by period, so test further: 
      if (sResult.Length == sResult.LastIndexOf("*")+1) 
      { 
       // Second asterisk is the last character, so good search pattern. 
       bResult = true; 
      } 
     } 
    } 
}