webentwicklung-frage-antwort-db.com.de

Sie müssen eine Wildcard-Suche (*,?, Usw.) für eine Zeichenfolge mit Regex durchführen

Ich muss eine Wildcard-Suche (*, ? usw.) auf einer Zeichenfolge durchführen.

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");
}

Mit dem obigen Code schlägt "Found" -Block aber eigentlich sollte es nicht!

Wenn mein Muster "e *" ist, sollte nur "Gefunden" getroffen werden.

Mein Verständnis oder meine Anforderung ist, dass d * search den Text finden soll, der "d" gefolgt von beliebigen Zeichen enthält.

Soll ich mein Muster als "d. *" Und "e. *" Ändern? Gibt es in .NET Unterstützung für Wild Card, die intern während der Verwendung der Regex-Klasse erfolgt?

58
Scott

Von http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx :

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

Etwas wie foo*.xls? wird also in ^foo.*\.xls.$ umgewandelt.

114
Gabe

Sie können einen einfachen Platzhalter ohne RegEx mit einer Visual Basic-Funktion namens LikeString ausführen.

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

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

Wenn Sie CompareMethod.Text verwenden, wird zwischen Groß- und Kleinschreibung unterschieden. Für den Vergleich zwischen Groß- und Kleinschreibung können Sie CompareMethod.Binary verwenden.

Mehr Infos hier: 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

21
Adam Szabo

Die korrekte Formulierung für reguläre Ausdrücke des Glob-Ausdrucks d* lautet ^d, was mit allem übereinstimmt, was mit d beginnt.

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

(Das @-Anführungszeichen ist in diesem Fall nicht erforderlich, ist jedoch empfehlenswert, da viele reguläre Ausdrücke umgekehrte Schrägstriche verwenden, die allein gelassen werden müssen, und sie zeigen dem Leser auch an, dass dieser String speziell ist.

10
Mark Lakata

Windows und * Nux behandeln Wildcards unterschiedlich. *, ? und . werden von Windows auf sehr komplexe Weise verarbeitet, die Anwesenheit oder Position eines Benutzers würde die Bedeutung eines anderen ändern. Während * nux es einfach hält, ist es nur ein einfaches Mustermatch. Außerdem stimmt Windows für 0 oder 1 Zeichen mit ? überein, Linux für genau 1 Zeichen.

Ich habe keine maßgeblichen Dokumente zu diesem Thema gefunden, hier nur meine Schlussfolgerung, basierend auf den Tagen der Tests unter Windows 8/XP (Befehlszeile, dir-Befehl, um genau zu sein, und die Directory.GetFiles-Methode verwendet auch dieselben Regeln) und Ubuntu Server 12.04 .1 (ls-Befehl). Ich habe Dutzende häufiger und ungewöhnlicher Fälle zum Laufen gebracht, obwohl es auch viele gescheiterte Fälle gibt.

Die aktuelle Antwort von Gabe funktioniert wie * nux. Wenn Sie auch einen Windows-Stil haben möchten und die Unvollkommenheit akzeptieren möchten, dann hier:

    /// <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);
    }

Es ist eine komische Sache, sogar die Windows-API PathMatchSpec stimmt nicht mit FindFirstFile überein. Versuchen Sie es einfach mit a1*., FindFirstFile sagt, dass es mit a1 übereinstimmt, PathMatchSpec sagt nicht.

6
deerchao

d* bedeutet, dass es mit null oder mehr "d" Zeichen übereinstimmen sollte. Jede Zeichenfolge ist also eine gültige Übereinstimmung. Versuchen Sie stattdessen d+!

Um Unterstützung für Platzhaltermuster zu haben, würde ich die Platzhalterzeichen durch die RegEx-Entsprechungen ersetzen. Wie * wird .* und ? wird .?. Dann wird Ihr Ausdruck zu d.*.

3
Anders Zommarin

Sie müssen Ihren Platzhalterausdruck in einen regulären Ausdruck konvertieren. Zum Beispiel:

    private bool WildcardMatch(String s, String wildcard, bool case_sensitive)
    {
        // Replace the * with an .* and the ? with a dot. Put ^ at the
        // beginning and a $ at the end
        String pattern = "^" + Regex.Escape(wildcard).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";

        // Now, run the Regex as you already know
        Regex regex;
        if(case_sensitive)
            regex = new Regex(pattern);
        else
            regex = new Regex(pattern, RegexOptions.IgnoreCase);

        return(regex.IsMatch(s));
    } 
3
carlos357

Sie müssen spezielle Regex-Symbole im Eingabe-Platzhalter-Muster mit Escapezeichen versehen (beispielsweise entspricht Muster *.txt^.*\.txt$) Schrägstriche, Klammern und viele Sonderzeichen müssen durch @"\" + s ersetzt werden, wobei s - spezielles Regex-Symbol.

3
Camarada

Der obere Code ist nicht bis zum Ende korrekt.

Dies liegt daran, dass Sie bei der Suche nach zz * foo * oder zz * keine korrekten Ergebnisse erhalten.

Und wenn Sie "abcd *" in "abcd" in TotalCommander suchen, wird er eine abcd-Datei finden, sodass der gesamte obere Code falsch ist.

Hier ist der richtige Code.

public string WildcardToRegex(string pattern)
{             
    string result= Regex.Escape(pattern).
        Replace(@"\*", ".+?").
        Replace(@"\?", "."); 

    if (result.EndsWith(".+?"))
    {
        result = result.Remove(result.Length - 3, 3);
        result += ".*";
    }

    return result;
}
0
user3816530

Möglicherweise möchten Sie WildcardPattern von System.Management.Automation Assembly verwenden. Siehe meine Antwort hier .

0
VirtualVDX

Ich denke, @Dmitri hat eine nette Lösung unter Übereinstimmende Zeichenfolgen mit Platzhalterzeichenhttps://stackoverflow.com/a/30300521/1726296

Basierend auf seiner Lösung habe ich zwei Erweiterungsmethoden erstellt. (Kredit geht an ihn)

Kann hilfreich sein.

public static String WildCardToRegular(this String value)
{
        return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}

public static bool WildCardMatch(this String value,string pattern,bool ignoreCase = true)
{
        if (ignoreCase)
            return Regex.IsMatch(value, WildCardToRegular(pattern), RegexOptions.IgnoreCase);

        return Regex.IsMatch(value, WildCardToRegular(pattern));
}

Verwendungszweck:

string pattern = "file.*";

var isMatched = "file.doc".WildCardMatch(pattern)

oder

string xlsxFile = "file.xlsx"
var isMatched = xlsxFile.WildCardMatch(pattern)
0
Tejasvi Hegde