соответствие шаблону глобуса в .NET - PullRequest
43 голосов
/ 09 октября 2008

Есть ли в .NET встроенный механизм для сопоставления с шаблонами, отличными от регулярных выражений? Я хотел бы сопоставить с использованием подстановочных знаков стиля UNIX (glob) (* = любое количество любого символа).

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

Ответы [ 14 ]

62 голосов
/ 10 ноября 2010

Мне нравится мой код немного более семантическим, поэтому я написал этот метод расширения:

using System.Text.RegularExpressions;

namespace Whatever
{
    public static class StringExtensions
    {
        /// <summary>
        /// Compares the string against a given pattern.
        /// </summary>
        /// <param name="str">The string.</param>
        /// <param name="pattern">The pattern to match, where "*" means any sequence of characters, and "?" means any single character.</param>
        /// <returns><c>true</c> if the string matches the given pattern; otherwise <c>false</c>.</returns>
        public static bool Like(this string str, string pattern)
        {
            return new Regex(
                "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$",
                RegexOptions.IgnoreCase | RegexOptions.Singleline
            ).IsMatch(str);
        }
    }
}

(изменить пространство имен и / или скопировать метод расширения в свой собственный класс расширений строки)

Используя это расширение, вы можете написать следующее:

if (File.Name.Like("*.jpg"))
{
   ....
}

Просто сахар, чтобы сделать ваш код немного более разборчивым: -)

34 голосов
/ 10 октября 2008

Я нашел фактический код для вас:

Regex.Escape( wildcardExpression ).Replace( @"\*", ".*" ).Replace( @"\?", "." );
22 голосов
/ 03 июня 2016

Просто для полноты картины. С 2016 года в dotnet core появился новый пакет nuget под названием Microsoft.Extensions.FileSystemGlobbing, который поддерживает расширенные пути перемещения. ( Nuget Package )

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

  • wwwroot/app/**/*.module.js
  • wwwroot/app/**/*.js

Это работает несколько схоже с тем, что .gitignore файлы используют, чтобы определить, какие файлы исключить из системы контроля версий.

10 голосов
/ 25 августа 2010

Варианты методов с 2 и 3 аргументами, такие как GetFiles() и EnumerateDirectories(), принимают строку поиска в качестве второго аргумента, поддерживающего глобализацию имени файла, с * и ?.

class GlobTestMain
{
    static void Main(string[] args)
    {
        string[] exes = Directory.GetFiles(Environment.CurrentDirectory, "*.exe");
        foreach (string file in exes)
        {
            Console.WriteLine(Path.GetFileName(file));
        }
    }
}

даст

GlobTest.exe
GlobTest.vshost.exe

В документах указано, что есть несколько предупреждений с соответствующими расширениями. В нем также говорится, что имена файлов 8.3 сопоставляются (которые могут быть сгенерированы автоматически за кулисами), что может привести к «дублирующим» совпадениям в заданных некоторых шаблонах.

Методы, поддерживающие это: GetFiles(), GetDirectories() и GetFileSystemEntries(). Варианты Enumerate также поддерживают это.

5 голосов
/ 09 октября 2008

Если вы используете VB.Net, вы можете использовать оператор Like с синтаксисом типа Glob.

http://www.getdotnetcode.com/gdncstore/free/Articles/Intoduction%20to%20the%20VB%20NET%20Like%20Operator.htm

4 голосов
/ 05 марта 2009

Я написал FileSelector класс, который делает выбор файлов на основе имен файлов. Он также выбирает файлы на основе времени, размера и атрибутов. Если вы просто хотите, чтобы имя файла отображалось как-то иначе, вы выражаете имя в таких формах, как «* .txt» и т. П. Если вам нужны другие параметры, вы указываете логическую инструкцию типа «name = * .xls and ctime <2009-01-01», что подразумевает файл .xls, созданный до 1 января 2009 г. «name! = * .xls» означает все файлы, которые не являются xls. </p>

Проверьте это. Открытый исходный код. Либеральная лицензия. Бесплатно использовать в другом месте.

3 голосов
/ 11 сентября 2018

Я написал глобальную библиотеку для .NETStandard, с тестами и тестами. Моя цель состояла в том, чтобы создать библиотеку для .NET с минимальными зависимостями, которая не использует Regex и превосходит Regex.

Вы можете найти его здесь:

3 голосов
/ 11 ноября 2011

Если вы хотите избежать регулярных выражений, это базовая глобальная реализация:

public static class Globber
{
    public static bool Glob(this string value, string pattern)
    {
        int pos = 0;

        while (pattern.Length != pos)
        {
            switch (pattern[pos])
            {
                case '?':
                    break;

                case '*':
                    for (int i = value.Length; i >= pos; i--)
                    {
                        if (Glob(value.Substring(i), pattern.Substring(pos + 1)))
                        {
                            return true;
                        }
                    }
                    return false;

                default:
                    if (value.Length == pos || char.ToUpper(pattern[pos]) != char.ToUpper(value[pos]))
                    {
                        return false;
                    }
                    break;
            }

            pos++;
        }

        return value.Length == pos;
    }
}

Используйте это так:

Assert.IsTrue("text.txt".Glob("*.txt"));
2 голосов
/ 06 августа 2017

https://www.nuget.org/packages/Glob.cs

https://github.com/mganss/Glob.cs

GNU Glob для .NET.

Вы можете избавиться от ссылки на пакет после установки и просто скомпилировать один исходный файл Glob.cs.

И поскольку это реализация GNU Glob, она кроссплатформенная и кросс-языковая, как только вы найдете другую похожую реализацию, наслаждайтесь!

1 голос
/ 04 августа 2010

Основываясь на предыдущих постах, я создал класс C #:

using System;
using System.Text.RegularExpressions;

public class FileWildcard
{
    Regex mRegex;

    public FileWildcard(string wildcard)
    {
        string pattern = string.Format("^{0}$", Regex.Escape(wildcard)
            .Replace(@"\*", ".*").Replace(@"\?", "."));
        mRegex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
    }
    public bool IsMatch(string filenameToCompare)
    {
        return mRegex.IsMatch(filenameToCompare);
    }
}

Использование этого будет выглядеть примерно так:

FileWildcard w = new FileWildcard("*.txt");
if (w.IsMatch("Doug.Txt"))
   Console.WriteLine("We have a match");

Соответствие НЕ совпадает с методом System.IO.Directory.GetFiles (), поэтому не используйте их вместе.

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