tags:

views:

129

answers:

4

Does anyone know if there's an equivalent functionality to the Windows API function PathMatchSpec() in .NET?

Thanks in advance

A: 

If you can't get the functionality using Regular Expressions (I believe this is the case) how about using PathMatchSpec() through PInvoke?

http://www.pinvoke.net/default.aspx/shlwapi/PathMatchSpec.html

Jay Riggs
A: 

You can try How to implement glob in C# or of course there's the PInvoke route if necessary.

Matthew Flaschen
A: 

I'm not aware of a method built in to .NET however it's trivial to duplicate with a Regex:

public static bool PathMatchSpec(String path, String spec)
{
    String specAsRegex = Regex.Escape(spec).Replace("\\*", ".*").Replace("\\?", ".") + "$";
    return Regex.IsMatch(path, specAsRegex);
}

Obviously this assumes the System.Text.RegularExpressions namespace is referenced. If you're going to do this alot with the same spec you could cache the Regex as well.

EDIT TO ADD: P/Invoke is indeed an option, but the signature for PathMatchSpec indicates it takes an ANSI string, so you'd be incurring a character set conversion for each invocation. Keep that in mind if you go that route. In that case PathMatchSpecEx would probably be preferable.

anelson
Cool... didn't know of the Escape() method myself; would definitely simplify part of my solution ;)
jerryjvl
A: 

In short... not that I know of... but maybe this can help you along (note, a bit lengthier than you might want, but it has served me well):

sealed public class WildcardMatch
{
    private static Regex wildcardFinder = new Regex(@"(?<wildcards>\?+|\*+)", RegexOptions.Compiled | RegexOptions.Singleline);
    private Regex wildcardRegex;

    public WildcardMatch(string wildcardFormat) : this(wildcardFormat, false) { }

    public WildcardMatch(string wildcardFormat, bool ignoreCase)
    {
        if (wildcardFormat == null)
            throw new ArgumentNullException("wildcardFormat");

        StringBuilder patternBuilder = new StringBuilder("^");
        MatchCollection matches = this.wildcardFinder.Matches(wildcardFormat);
        string[] split = this.wildcardFinder.Split(wildcardFormat);
        for (int ix = 0; ix < split.Length; ix++)
        {
            // Even indexes are literal text, odd indexes correspond to matches
            if (ix % 2 == 0)
                patternBuilder.Append(Regex.Escape(split[ix]));
            else
            {
                // Matches must be substituted with Regex control characters
                string wildcards = matches[ix / 2].Groups["wildcards"].Value;
                if (wildcards.StartsWith("*", StringComparison.Ordinal))
                    patternBuilder.Append("(.*)");
                else
                    patternBuilder.AppendFormat(CultureInfo.InvariantCulture, "({0})", wildcards.Replace('?', '.'));
            }
        }
        patternBuilder.Append("$");

        this.wildcardRegex = new Regex(
            patternBuilder.ToString(),
            RegexOptions.Singleline | (ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None));
    }

    public bool IsMatch(string value)
    {
        if (value == null)
            return false;

        return this.wildcardRegex.IsMatch(value);
    }

    public IEnumerable<string> ExtractMatches(string value)
    {
        if (value == null)
            yield break;

        Match match = this.wildcardRegex.Match(value);
        if (!match.Success)
            yield break;

        for (int ix = 1; ix < match.Groups.Count; ix++)
            yield return match.Groups[ix].Value;
    }
}
jerryjvl
Note that by using anelsons 'Regex.Escape()' the escaping code can definitely be simplified.
jerryjvl