68 votes

Besoin d'effectuer une recherche générique (*,?, Etc.) sur une chaîne à l'aide de Regex

J'ai besoin d'effectuer des caractères Génériques (*,?, etc) effectuer une recherche sur une chaîne de caractères. C'est ce que j'ai fait.

        string input = "Message";
        string pattern = "d*";
        Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);

        if (regex.IsMatch(input))
        {
            MessageBox.Show("Found");
        }
        else
        {
            MessageBox.Show("Not Found");
        }

Avec le code ci-dessus "Trouvé" bloc de frappe mais en fait il ne faut pas !

Si mon modèle est "e*", seuls les "Trouvé" devrait frapper.

Ma compréhension ou d'une exigence est d* rechercher le texte contenant "d", suivie de tous les caractères.

Dois-je changer mon patron que "d.*" et "e.*"? Est-il un soutien .NET pour la Wild Card qui à l'interne t-il tout en utilisant la classe Regex?

124voto

Gabe Points 49718

C'est pas difficile. De http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx :

 public static string WildcardToRegex(string pattern)
{
    return "^" + Regex.Escape(pattern)
                      .Replace(@"\*", ".*")
                      .Replace(@"\?", ".")
               + "$";
}
 

Donc, quelque chose comme foo*.xls? sera transformé en ^foo.*\.xls.$ .

22voto

user2270404 Points 1882

Vous pouvez faire un simple générique mach sans RegEx à l'aide d'une fonction Visual Basic appelé LikeString.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

if (Operators.LikeString("This is just a test", "*just*", CompareMethod.Text))
{
  Console.WriteLine("This matched!");
}

Si vous utilisez CompareMethod.Text il le compare à la casse. Pour comparaison sensible à la casse, vous pouvez utiliser CompareMethod.Binary.

Plus d'infos ici: http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C

MSDN: http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.likestring%28v=vs.100%29.ASPX

10voto

Mark Lakata Points 3458

La formulation correcte de l'expression globale d* est ^d , ce qui signifie que tout ce qui commence par d .

     string input = "Message";
    string pattern = @"^d";
    Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
 

(Les guillemets @ ne sont pas nécessaires dans ce cas, mais c'est une bonne pratique car de nombreuses expressions rationnelles utilisent des échappements avec une barre oblique inversée qu'il convient de ne pas modifier, et cela indique également au lecteur que cette chaîne est spéciale).

8voto

deerchao Points 5517

Windows et *nux traiter des caractères génériques différemment. *, ? et . sont traitées de manière très complexe par les Fenêtres, la présence ou la position de changement d'un autre sens. Alors que *nux reste simple, tout ce qu'il fait est juste une simple mise en correspondance du modèle. En outre, Windows matchs ? 0 ou 1 chars, Linux correspond exactement 1 caractères.

Je n'ai pas trouver des documents faisant autorité sur cette question, voici ma conclusion sur la base des jours de tests sur Windows 8/XP (ligne de commande, dir de la commande pour être plus précis, et l' Directory.GetFiles méthode utilise les mêmes règles trop) et le Serveur Ubuntu 12.04.1 (ls de la commande). J'ai fait des dizaines de communes et rares cas, les travaux, bien qu'il sont nombreux a échoué cas trop.

La réponse actuelle par Gabe, fonctionne comme *nux. Si vous aussi vous voulez un Windows le style, et sont prêts à accepter l'imperfection, alors ici, c'est:

    /// <summary>
    /// <para>Tests if a file name matches the given wildcard pattern, uses the same rule as shell commands.</para>
    /// </summary>
    /// <param name="fileName">The file name to test, without folder.</param>
    /// <param name="pattern">A wildcard pattern which can use char * to match any amount of characters; or char ? to match one character.</param>
    /// <param name="unixStyle">If true, use the *nix style wildcard rules; otherwise use windows style rules.</param>
    /// <returns>true if the file name matches the pattern, false otherwise.</returns>
    public static bool MatchesWildcard(this string fileName, string pattern, bool unixStyle)
    {
        if (fileName == null)
            throw new ArgumentNullException("fileName");

        if (pattern == null)
            throw new ArgumentNullException("pattern");

        if (unixStyle)
            return WildcardMatchesUnixStyle(pattern, fileName);

        return WildcardMatchesWindowsStyle(fileName, pattern);
    }

    private static bool WildcardMatchesWindowsStyle(string fileName, string pattern)
    {
        var dotdot = pattern.IndexOf("..", StringComparison.Ordinal);
        if (dotdot >= 0)
        {
            for (var i = dotdot; i < pattern.Length; i++)
                if (pattern[i] != '.')
                    return false;
        }

        var normalized = Regex.Replace(pattern, @"\.+$", "");
        var endsWithDot = normalized.Length != pattern.Length;

        var endWeight = 0;
        if (endsWithDot)
        {
            var lastNonWildcard = normalized.Length - 1;
            for (; lastNonWildcard >= 0; lastNonWildcard--)
            {
                var c = normalized[lastNonWildcard];
                if (c == '*')
                    endWeight += short.MaxValue;
                else if (c == '?')
                    endWeight += 1;
                else
                    break;
            }

            if (endWeight > 0)
                normalized = normalized.Substring(0, lastNonWildcard + 1);
        }

        var endsWithWildcardDot = endWeight > 0;
        var endsWithDotWildcardDot = endsWithWildcardDot && normalized.EndsWith(".");
        if (endsWithDotWildcardDot)
            normalized = normalized.Substring(0, normalized.Length - 1);

        normalized = Regex.Replace(normalized, @"(?!^)(\.\*)+$", @".*");

        var escaped = Regex.Escape(normalized);
        string head, tail;

        if (endsWithDotWildcardDot)
        {
            head = "^" + escaped;
            tail = @"(\.[^.]{0," + endWeight + "})?$";
        }
        else if (endsWithWildcardDot)
        {
            head = "^" + escaped;
            tail = "[^.]{0," + endWeight + "}$";
        }
        else
        {
            head = "^" + escaped;
            tail = "$";
        }

        if (head.EndsWith(@"\.\*") && head.Length > 5)
        {
            head = head.Substring(0, head.Length - 4);
            tail = @"(\..*)?" + tail;
        }

        var regex = head.Replace(@"\*", ".*").Replace(@"\?", "[^.]?") + tail;
        return Regex.IsMatch(fileName, regex, RegexOptions.IgnoreCase);
    }

    private static bool WildcardMatchesUnixStyle(string pattern, string text)
    {
        var regex = "^" + Regex.Escape(pattern)
                               .Replace("\\*", ".*")
                               .Replace("\\?", ".")
                    + "$";

        return Regex.IsMatch(text, regex);
    }

Il y a une drôle de chose, même de l'API Windows PathMatchSpec n'est pas d'accord avec FindFirstFile. Juste essayer de l' a1*., FindFirstFile dit qu'il corresponde a1, PathMatchSpec dit non.

6voto

Anders Zommarin Points 2357

d* signifie qu'il doit correspondre à zéro ou plusieurs caractères " d ". Donc, toute chaîne est une correspondance valide. Essayez d+ place!

Afin de prendre en charge les modèles de caractères génériques, je remplacerais les caractères génériques par les équivalents RegEx. Like * devient .* et ? devient .? . Ensuite, votre expression ci-dessus devient d.*

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X