Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
242 views
in Technique[技术] by (71.8m points)

c# - How to determine if a File Matches a File Mask?

I need to decide whether file name fits to file mask. The file mask could contain * or ? characters. Is there any simple solution for this?

bool bFits = Fits("myfile.txt", "my*.txt");

private bool Fits(string sFileName, string sFileMask)
    {
        ??? anything simple here ???
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I appreciate finding Joel's answer--saved me some time as well ! I did, however, have to make a few changes to make the method do what most users would expect:

  • I removed the 'this' keyword preceding the first argument. It does nothing here (though it could be useful if the method is intended to be an extension method, in which case it needs to be public and contained within a static class and itself be a static method).
  • I made the regular expression case-independent to match standard Windows wildcard behavior (so e.g. "c*.*" and "C*.*" both return the same result).
  • I added starting and ending anchors to the regular expression, again to match standard Windows wildcard behavior (so e.g. "stuff.txt" would be matched by "stuff*" or "s*" or "s*.*" but not by just "s").

private bool FitsMask(string fileName, string fileMask)
{
    Regex mask = new Regex(
        '^' + 
        fileMask
            .Replace(".", "[.]")
            .Replace("*", ".*")
            .Replace("?", ".")
        + '$',
        RegexOptions.IgnoreCase);
    return mask.IsMatch(fileName);
}

2009.11.04 Update: Match one of several masks

For even more flexibility, here is a plug-compatible method built on top of the original. This version lets you pass multiple masks (hence the plural on the second parameter name fileMasks) separated by lines, commas, vertical bars, or spaces. I wanted it so that I could let the user put as many choices as desired in a ListBox and then select all files matching any of them. Note that some controls (like a ListBox) use CR-LF for line breaks while others (e.g. RichTextBox) use just LF--that is why both " " and " " show up in the Split list.

private bool FitsOneOfMultipleMasks(string fileName, string fileMasks)
{
    return fileMasks
        .Split(new string[] {"
", "
", ",", "|", " "},
            StringSplitOptions.RemoveEmptyEntries)
        .Any(fileMask => FitsMask(fileName, fileMask));
}

2009.11.17 Update: Handle fileMask inputs more gracefully

The earlier version of FitsMask (which I have left in for comparison) does a fair job but since we are treating it as a regular expression it will throw an exception if it is not a valid regular expression when it comes in. The solution is that we actually want any regex metacharacters in the input fileMask to be considered literals, not metacharacters. But we still need to treat period, asterisk, and question mark specially. So this improved version of FitsMask safely moves these three characters out of the way, transforms all remaining metacharacters into literals, then puts the three interesting characters back, in their "regex'ed" form.

One other minor improvement is to allow for case-independence, per standard Windows behavior.

private bool FitsMask(string fileName, string fileMask)
{
    string pattern =
         '^' + 
         Regex.Escape(fileMask.Replace(".", "__DOT__")
                         .Replace("*", "__STAR__")
                         .Replace("?", "__QM__"))
             .Replace("__DOT__", "[.]")
             .Replace("__STAR__", ".*")
             .Replace("__QM__", ".")
         + '$';
    return new Regex(pattern, RegexOptions.IgnoreCase).IsMatch(fileName);
}

2010.09.30 Update: Somewhere along the way, passion ensued...

I have been remiss in not updating this earlier but these references will likely be of interest to readers who have made it to this point:

  • I embedded the FitsMask method as the heart of a WinForms user control aptly called a FileMask--see the API here.
  • I then wrote an article featuring the FileMask control published on Simple-Talk.com, entitled Using LINQ Lambda Expressions to Design Customizable Generic Components. (While the method itself does not use LINQ, the FileMask user control does, hence the title of the article.)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...