.net 如何检查文件名是否与通配符模式匹配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/652037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:20:35  来源:igfitidea点击:

How do I check if a filename matches a wildcard pattern

regex.net

提问by Jonathan Allen

I've got a wildcard pattern, perhaps "*.txt" or "POS??.dat".

我有一个通配符模式,可能是“*.txt”或“POS??.dat”。

I also have list of filenames in memory that I need to compare to that pattern.

我还有内存中的文件名列表,需要与该模式进行比较。

How would I do that, keeping in mind I need exactly the same semantics that IO.DirectoryInfo.GetFiles(pattern) uses.

我将如何做到这一点,请记住我需要与 IO.DirectoryInfo.GetFiles(pattern) 使用的语义完全相同的语义。

EDIT: Blindly translating this into a regex will NOT work.

编辑:盲目地将其转换为正则表达式是行不通的。

回答by sprite

I have a complete answer in code for you that's 95% like FindFiles(string).

我有一个完整的代码答案给你,95% 喜欢FindFiles(string).

The 5% that isn't there is the short names/long names behavior in the second note on the MSDNdocumentation for this function.

MSDN文档的第二个注释中,没有这个功能的 5% 是短名称/长名称行为。

If you would still like to get that behavior, you'll have to complete a computation of the short name of each string you have in the input array, and then add the long name to the collection of matches if either the long or short name matches the pattern.

如果您仍然希望获得该行为,则必须完成对输入数组中每个字符串的短名称的计算,然后将长名称添加到匹配集合中(如果是长名称或短名称)匹配模式。

Here is the code:

这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace FindFilesRegEx
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "hello.t", "HelLo.tx", "HeLLo.txt", "HeLLo.txtsjfhs", "HeLLo.tx.sdj", "hAlLo20984.txt" };
            string[] matches;
            matches = FindFilesEmulator("hello.tx", names);
            matches = FindFilesEmulator("H*o*.???", names);
            matches = FindFilesEmulator("hello.txt", names);
            matches = FindFilesEmulator("lskfjd30", names);
        }

        public string[] FindFilesEmulator(string pattern, string[] names)
        {
            List<string> matches = new List<string>();
            Regex regex = FindFilesPatternToRegex.Convert(pattern);
            foreach (string s in names)
            {
                if (regex.IsMatch(s))
                {
                    matches.Add(s);
                }
            }
            return matches.ToArray();
        }

        internal static class FindFilesPatternToRegex
        {
            private static Regex HasQuestionMarkRegEx   = new Regex(@"\?", RegexOptions.Compiled);
            private static Regex IllegalCharactersRegex  = new Regex("[" + @"\/:<>|" + "\"]", RegexOptions.Compiled);
            private static Regex CatchExtentionRegex    = new Regex(@"^\s*.+\.([^\.]+)\s*$", RegexOptions.Compiled);
            private static string NonDotCharacters      = @"[^.]*";
            public static Regex Convert(string pattern)
            {
                if (pattern == null)
                {
                    throw new ArgumentNullException();
                }
                pattern = pattern.Trim();
                if (pattern.Length == 0)
                {
                    throw new ArgumentException("Pattern is empty.");
                }
                if(IllegalCharactersRegex.IsMatch(pattern))
                {
                    throw new ArgumentException("Pattern contains illegal characters.");
                }
                bool hasExtension = CatchExtentionRegex.IsMatch(pattern);
                bool matchExact = false;
                if (HasQuestionMarkRegEx.IsMatch(pattern))
                {
                    matchExact = true;
                }
                else if(hasExtension)
                {
                    matchExact = CatchExtentionRegex.Match(pattern).Groups[1].Length != 3;
                }
                string regexString = Regex.Escape(pattern);
                regexString = "^" + Regex.Replace(regexString, @"\\*", ".*");
                regexString = Regex.Replace(regexString, @"\\?", ".");
                if(!matchExact && hasExtension)
                {
                    regexString += NonDotCharacters;
                }
                regexString += "$";
                Regex regex = new Regex(regexString, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                return regex;
            }
        }
    }
}

回答by toddmo

You can simply do this. You do not need regular expressions.

你可以简单地做到这一点。您不需要正则表达式。

using Microsoft.VisualBasic.CompilerServices;

if (Operators.LikeString("pos123.txt", "pos?23.*", CompareMethod.Text))
{
  Console.WriteLine("Filename matches pattern");
}

Or, in VB.Net,

或者,在 VB.Net 中,

If "pos123.txt" Like "pos?23.*" Then
  Console.WriteLine("Filename matches pattern")
End If

In c# you could simulate this with an extension method. It wouldn't be exactly like VB Like, but it would be like...very cool.

在 c# 中,您可以使用扩展方法模拟这一点。它不会完全像 VB Like,但它会像......非常酷。

回答by Guffa

You could translate the wildcards into a regular expression:

您可以将通配符转换为正则表达式:

*.txt -> ^.+\.txt$

POS??.dat _> ^POS..\.dat$

Use the Regex.Escapemethod to escape the characters that are not wildcars into literal strings for the pattern (e.g. converting ".txt"to "\.txt").

使用Regex.Escape方法将不是通配符的字符转义为模式的文字字符串(例如转换".txt""\.txt")。

The wildcard *translates into .+, and ?translates into .

通配符*转换为.+,并?转换为.

Put ^ at the beginning of the pattern to match the beginning of the string, and $ at the end to match the end of the string.

将 ^ 放在模式的开头以匹配字符串的开头,将 $ 放在结尾以匹配字符串的结尾。

Now you can use the Regex.IsMatchmethod to check if a file name matches the pattern.

现在您可以使用该Regex.IsMatch方法检查文件名是否与模式匹配。

回答by zweiterlinde

Some kind of regex/glob is the way to go, but there are some subtleties; your question indicates you want identical semantics to IO.DirectoryInfo.GetFiles. That could be a challenge, because of the special cases involving 8.3 vs. long file names and the like. The whole story is on MSDN.

某种正则表达式/glob 是要走的路,但有一些微妙之处;你的问题表明你想要相同的语义IO.DirectoryInfo.GetFiles。这可能是一个挑战,因为涉及 8.3 与长文件名等的特殊情况。整个故事都在MSDN 上

If you don't need an exact behavioral match, there are a couple of good SO questions:

如果您不需要精确的行为匹配,那么有几个很好的 SO 问题:

glob pattern matching in .NET
How to implement glob in C#

.NET 中的 glob 模式匹配
如何在 C# 中实现 glob

回答by jgerman

For anyone who comes across this question now that it is years later, I found over at the MSDN social boards that the GetFiles() method will accept * and ? wildcard characters in the searchPattern parameter. (At least in .Net 3.5, 4.0, and 4.5)

对于现在几年后遇到这个问题的任何人,我在 MSDN 社交论坛上发现 GetFiles() 方法将接受 * 和 ? searchPattern 参数中的通配符。(至少在 .Net 3.5、4.0 和 4.5 中)

Directory.GetFiles(string path, string searchPattern)

http://msdn.microsoft.com/en-us/library/wz42302f.aspx

http://msdn.microsoft.com/en-us/library/wz42302f.aspx

回答by Bruce Engle

Just call the Windows API function PathMatchSpecExW().

只需调用 Windows API 函数 PathMatchSpecExW()。

[Flags]
public enum MatchPatternFlags : uint
{
    Normal          = 0x00000000,   // PMSF_NORMAL
    Multiple        = 0x00000001,   // PMSF_MULTIPLE
    DontStripSpaces = 0x00010000    // PMSF_DONT_STRIP_SPACES
}

class FileName
{
    [DllImport("Shlwapi.dll", SetLastError = false)]
    static extern int PathMatchSpecExW([MarshalAs(UnmanagedType.LPWStr)] string file,
                                       [MarshalAs(UnmanagedType.LPWStr)] string spec,
                                       MatchPatternFlags flags);

    /*******************************************************************************
    * Function:     MatchPattern
    *
    * Description:  Matches a file name against one or more file name patterns.
    *
    * Arguments:    file - File name to check
    *               spec - Name pattern(s) to search foe
    *               flags - Flags to modify search condition (MatchPatternFlags)
    *
    * Return value: Returns true if name matches the pattern.
    *******************************************************************************/

    public static bool MatchPattern(string file, string spec, MatchPatternFlags flags)
    {
        if (String.IsNullOrEmpty(file))
            return false;

        if (String.IsNullOrEmpty(spec))
            return true;

        int result = PathMatchSpecExW(file, spec, flags);

        return (result == 0);
    }
}

回答by kewljibin

Plz try the below code.

请尝试以下代码。

static void Main(string[] args)
    {
        string _wildCardPattern = "*.txt";

        List<string> _fileNames = new List<string>();
        _fileNames.Add("text_file.txt");
        _fileNames.Add("csv_file.csv");

        Console.WriteLine("\nFilenames that matches [{0}] pattern are : ", _wildCardPattern);
        foreach (string _fileName in _fileNames)
        {
            CustomWildCardPattern _patetrn = new CustomWildCardPattern(_wildCardPattern);
            if (_patetrn.IsMatch(_fileName))
            {
                Console.WriteLine("{0}", _fileName);
            }
        }

    }

public class CustomWildCardPattern : Regex
{
    public CustomWildCardPattern(string wildCardPattern)
        : base(WildcardPatternToRegex(wildCardPattern))
    {
    }

    public CustomWildCardPattern(string wildcardPattern, RegexOptions regexOptions)
        : base(WildcardPatternToRegex(wildcardPattern), regexOptions)
    {
    }

    private static string WildcardPatternToRegex(string wildcardPattern)
    {
        string patternWithWildcards = "^" + Regex.Escape(wildcardPattern).Replace("\*", ".*");
        patternWithWildcards = patternWithWildcards.Replace("\?", ".") + "$";
        return patternWithWildcards;
    }
}

回答by Martin P.

The use of RegexOptions.IgnoreCase will fix it.

使用 RegexOptions.IgnoreCase 将修复它。

public class WildcardPattern : Regex {
    public WildcardPattern(string wildCardPattern)
        : base(ConvertPatternToRegex(wildCardPattern), RegexOptions.IgnoreCase) {
    }

    public WildcardPattern(string wildcardPattern, RegexOptions regexOptions)
        : base(ConvertPatternToRegex(wildcardPattern), regexOptions) {
    }

    private static string ConvertPatternToRegex(string wildcardPattern) {
        string patternWithWildcards = Regex.Escape(wildcardPattern).Replace("\*", ".*");
        patternWithWildcards = string.Concat("^", patternWithWildcards.Replace("\?", "."), "$");
        return patternWithWildcards;
    }
}