Как проверить, соответствует ли имя файла шаблону подстановки - PullRequest
26 голосов
/ 16 марта 2009

У меня есть шаблон подстановки, возможно, «* .txt» или «POS ??. Dat».

У меня также есть список имен файлов в памяти, которые мне нужно сравнить с этим шаблоном.

Как мне это сделать, помня, что мне нужна точно такая же семантика, которую использует IO.DirectoryInfo.GetFiles (pattern).

РЕДАКТИРОВАТЬ: Слепой перевод этого в регулярное выражение не будет работать.

Ответы [ 8 ]

43 голосов
/ 07 декабря 2010

У меня есть полный ответ в коде для вас, который на 95% похож на FindFiles(string).

5%, которого нет, это поведение коротких имен / длинных имен во второй заметке в документации MSDN для этой функции.

Если вы все еще хотели бы получить такое поведение, вам придется завершить вычисление короткого имени каждой строки во входном массиве, а затем добавить длинное имя в коллекцию совпадений, если либо длинный или короткое имя соответствует шаблону.

Вот код:

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;
            }
        }
    }
}
11 голосов
/ 27 сентября 2014

Вы можете просто сделать это. Вам не нужны регулярные выражения.

using Microsoft.VisualBasic.CompilerServices;

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

Или, в VB.Net,

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

В c # вы можете смоделировать это с помощью метода расширения. Это не будет похоже на VB Like, но это будет ... очень круто.

2 голосов
/ 16 марта 2009

Какой-то тип регулярного выражения / глобуса - это путь, но есть некоторые тонкости; Ваш вопрос указывает на то, что вы хотите идентичную семантику IO.DirectoryInfo.GetFiles. Это может быть проблемой из-за особых случаев, связанных с 8.3, длинными именами файлов и т.п. Вся история на MSDN .

Если вам не нужно точное поведенческое совпадение, есть пара хороших вопросов SO:

соответствие шаблону глобуса в .NET
Как реализовать glob в C #

2 голосов
/ 16 марта 2009

Вы можете перевести символы подстановки в регулярное выражение:

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

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

Используйте метод Regex.Escape, чтобы экранировать символы, которые не являются символами подстановки, в буквальные строки для шаблона (например, преобразование ".txt" в "\.txt").

Подстановочный знак * переводится в .+, а ? переводится в .

Поместите ^ в начало шаблона, чтобы соответствовать началу строки, и $ в конце, чтобы соответствовать концу строки.

Теперь вы можете использовать метод Regex.IsMatch, чтобы проверить, соответствует ли имя файла шаблону.

1 голос
/ 01 апреля 2014

Для тех, кто сталкивается с этим вопросом сейчас, когда это происходит спустя годы, я обнаружил в социальных сетях 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

0 голосов
/ 17 января 2014

Использование 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;
    }
}
0 голосов
/ 07 декабря 2010

Плз попробуйте следующий код.

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;
    }
}
0 голосов
/ 16 марта 2009

Просто используйте класс Regex. Инициализируйте его с шаблоном подстановочных знаков, о котором вы думаете, а затем используйте метод .IsMatch (filename), чтобы проверить каждое имя файла, чтобы увидеть, соответствует ли оно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...