3

I know I can do

Directory.GetFiles(@"c:\", "*.html")

and I'll get a list of files that match the *.html file pattern.

I'd like to do the inverse. Given file name abc.html, I'd like a method that will tell me if that filename matches the *.html pattern. for instance

class.method("abc.html", "*.html") // returns true
class.method("abc.xml", "*.html") // returns false
class.method("abc.doc", "*.?oc") // returns true
class.method("Jan24.txt", "Jan*.txt") // returns true
class.method("Dec24.txt", "Jan*.txt") // returns false

The functionality must exist in dotnet. I just don't know where it's exposed.

Converting the pattern to regex could be one way to go. However it just seems like there are a lot of edge cases and may be more trouble than it's worth.

Note: the filename in questions may not exist yet, so I can't just wrap a Directory.GetFiles call and check to see if the result set has any entries.

Aheho
  • 12,622
  • 13
  • 54
  • 83

2 Answers2

9

Easiest way to go is to convert your wildcard to regex, and then apply it:

public static string WildcardToRegex(string pattern)
{
  return "^" + Regex.Escape(pattern).
  Replace("\\*", ".*").
  Replace("\\?", ".") + "$";
}

But if you cannot use regex for some reason, you can write your own implementation of wildcard matching. You can find one here.

Here's another one ported from python implementation (Edit 2020-07: fixed IndexOutOfRangeException):

using System;
    
class App
{
  static void Main()
  {
    Console.WriteLine(Match("abc.html", "*.html")); // returns true
    Console.WriteLine(Match("abc.xml", "*.html")); // returns false
    Console.WriteLine(Match("abc.doc", "*.?oc")); // returns true
    Console.WriteLine(Match("Jan24.txt", "Jan*.txt")); // returns true
    Console.WriteLine(Match("Dec24.txt", "Jan*.txt")); // returns false  
  }
    
  static bool Match(string s1, string s2)
  {
    if (s2=="*" || s1==s2) return true;
    if (s1=="" || s2=="") return false;

    if (s1[0]==s2[0] || s2[0]=='?') return Match(s1.Substring(1),s2.Substring(1));
    if (s2[0]=='*') return Match(s1.Substring(1),s2) || Match(s1,s2.Substring(1));
    return false;
  }
}
mlist
  • 33
  • 2
  • 6
Alexander
  • 4,153
  • 1
  • 24
  • 37
  • This won't work for invalid filenames. `Match("aaa/bbb.txt", "*.txt");` will return *true* – I4V Mar 26 '13 at 21:50
  • 1
    Original question does not include path, only file name matching. But you can always extract file name using Path.GetFileName(). – Alexander Mar 27 '13 at 07:20
  • I said **invalid** filenames like `aaa/bbb.txt`. Not *path* – I4V Mar 27 '13 at 16:54
  • 2
    @I4V: I think it's not purpose of this RegEx, you can for invalid filename characters before doing the Match, searching for Path.GetInvalidFileNameChars. – Stefano May 27 '14 at 13:04
0

I don't think searchPattern of GetFiles does support full regex. Below code can be an alternative(but not very performant)

bool IsMatch(string fileName,string searchPattern)
{
    try
    {
        var di = Directory.CreateDirectory("_TEST_");
        string fullName = Path.Combine(di.FullName, fileName);
        using (File.Create(fullName)) ;
        bool isMatch = di.GetFiles(searchPattern).Any();
        File.Delete(fullName);
        return isMatch;
    }
    catch
    {
        return false;
    }
}
I4V
  • 34,891
  • 6
  • 67
  • 79