Overeenkomende tekenreeksen met jokerteken

Ik wil strings matchen met een wildcard (*), waarbij de wildcard “elke” betekent. Bijvoorbeeld:

*X = string must end with X
X* = string must start with X
*X* = string must contain X

Ook sommige samengestelde toepassingen zoals:

*X*YZ* = string contains X and contains YZ
X*YZ*P = string starts with X, contains YZ and ends with P.

Is er een eenvoudig algoritme om dit te doen? Ik weet niet zeker of ik regex moet gebruiken (hoewel het een mogelijkheid is).

Ter verduidelijking, de gebruikers zullen het bovenstaande typen in een filtervak ​​(een zo eenvoudig mogelijke filter), ik wil niet dat ze zelf reguliere expressies moeten schrijven. Dus iets dat ik gemakkelijk kan transformeren van de bovenstaande notatie zou goed zijn.


Antwoord 1, autoriteit 100%

Vaak werken jokers met tweetypen jokers:

 ? - any character  (one and only one)
  * - any characters (zero or more)

zodat u deze regels gemakkelijk kunt omzetten in de juiste gewone uitdrukkingn:

// If you want to implement both "*" and "?"
private static String WildCardToRegular(String value) {
  return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$"; 
}
// If you want to implement "*" only
private static String WildCardToRegular(String value) {
  return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$"; 
}

En dan kun je Regexzoals gewoonlijk gebruiken:

 String test = "Some Data X";
  Boolean endsWithEx = Regex.IsMatch(test, WildCardToRegular("*X"));
  Boolean startsWithS = Regex.IsMatch(test, WildCardToRegular("S*"));
  Boolean containsD = Regex.IsMatch(test, WildCardToRegular("*D*"));
  // Starts with S, ends with X, contains "me" and "a" (in that order) 
  Boolean complex = Regex.IsMatch(test, WildCardToRegular("S*me*a*X"));

Antwoord 2, autoriteit 21%

Je zou de VB.NET Like-Operatorkunnen gebruiken:

string text = "x is not the same as X and yz not the same as YZ";
bool contains = LikeOperator.LikeString(text,"*X*YZ*", Microsoft.VisualBasic.CompareMethod.Binary);  

Gebruik CompareMethod.Textals u de case wilt negeren.

Je moet using Microsoft.VisualBasic.CompilerServices;en voeg een verwijzing toe naar de Microsoft.VisualBasic.dll.

Aangezien het deel uitmaakt van het .NET-framework en dat altijd zal blijven, is het geen probleem om deze klasse te gebruiken.


Antwoord 3, autoriteit 12%

Gebruik van WildcardPatternvan System.Management.Automationkan een optie zijn.

pattern = new WildcardPattern(patternString);
pattern.IsMatch(stringToMatch);

De gebruikersinterface van Visual Studio staat u misschien niet toe om System.Management.Automation-assembly toe te voegen aan referenties van uw project. Voel je vrij om het handmatig toe te voegen, zoals hierbeschreven.


Antwoord 4, autoriteit 8%

Voor degenen die .NET Core 2.1+ of .NET 5+ gebruiken, kunt u de FileSystemName.MatchesSimpleExpressionmethode in de System.IO.Enumeration naamruimte.

string text = "X is a string with ZY in the middle and at the end is P";
bool isMatch = FileSystemName.MatchesSimpleExpression("X*ZY*P", text);

Beide parameters zijn eigenlijk ReadOnlySpan<char>maar u kunt ook stringargumenten gebruiken. Er is ook een overbelaste methode als je case-matching wilt in- of uitschakelen. Het is standaard niet hoofdlettergevoelig, zoals Chris vermeldde in de opmerkingen.


Antwoord 5, autoriteit 4%

Een wildcard *kan worden vertaald als .*of .*?regex-patroon.

Misschien moet u een enkele regelmodus gebruiken om nieuwe regelsymbolen te matchen, en in dit geval kunt u (?s)gebruiken als onderdeel van het regex-patroon.

Je kunt het voor het hele patroon of een deel van het patroon instellen:

X* = > @"X(?s:.*)"
*X = > @"(?s:.*)X"
*X* = > @"(?s).*X.*"
*X*YZ* = > @"(?s).*X.*YZ.*"
X*YZ*P = > @"(?s:X.*YZ.*P)"

Antwoord 6, autoriteit 3%

*X*YZ* = string contains X and contains YZ

@".*X.*YZ"

X*YZ*P = string starts with X, contains YZ and ends with P.

@"^X.*YZ.*P$"

Antwoord 7, autoriteit 2%

Het is noodzakelijk om er rekening mee te houden dat Regex IsMatch true geeft met XYZ, bij het controleren van match met Y*. Om dit te vermijden, gebruik ik “^” anker

isMatch(str1, "^" + str2.Replace("*", ".*?"));  

Dus de volledige code om uw probleem op te lossen is

   bool isMatchStr(string str1, string str2)
    {
        string s1 = str1.Replace("*", ".*?");
        string s2 = str2.Replace("*", ".*?");
        bool r1 = Regex.IsMatch(s1, "^" + s2);
        bool r2 = Regex.IsMatch(s2, "^" + s1);
        return r1 || r2;
    }

Antwoord 8

public class Wildcard
{
    private readonly string _pattern;
    public Wildcard(string pattern)
    {
        _pattern = pattern;
    }
    public static bool Match(string value, string pattern)
    {
        int start = -1;
        int end = -1;
        return Match(value, pattern, ref start, ref end);
    }
    public static bool Match(string value, string pattern, char[] toLowerTable)
    {
        int start = -1;
        int end = -1;
        return Match(value, pattern, ref start, ref end, toLowerTable);
    }
    public static bool Match(string value, string pattern, ref int start, ref int end)
    {
        return new Wildcard(pattern).IsMatch(value, ref start, ref end);
    }
    public static bool Match(string value, string pattern, ref int start, ref int end, char[] toLowerTable)
    {
        return new Wildcard(pattern).IsMatch(value, ref start, ref end, toLowerTable);
    }
    public bool IsMatch(string str)
    {
        int start = -1;
        int end = -1;
        return IsMatch(str, ref start, ref end);
    }
    public bool IsMatch(string str, char[] toLowerTable)
    {
        int start = -1;
        int end = -1;
        return IsMatch(str, ref start, ref end, toLowerTable);
    }
    public bool IsMatch(string str, ref int start, ref int end)
    {
        if (_pattern.Length == 0) return false;
        int pindex = 0;
        int sindex = 0;
        int pattern_len = _pattern.Length;
        int str_len = str.Length;
        start = -1;
        while (true)
        {
            bool star = false;
            if (_pattern[pindex] == '*')
            {
                star = true;
                do
                {
                    pindex++;
                }
                while (pindex < pattern_len && _pattern[pindex] == '*');
            }
            end = sindex;
            int i;
            while (true)
            {
                int si = 0;
                bool breakLoops = false;
                for (i = 0; pindex + i < pattern_len && _pattern[pindex + i] != '*'; i++)
                {
                    si = sindex + i;
                    if (si == str_len)
                    {
                        return false;
                    }
                    if (str[si] == _pattern[pindex + i])
                    {
                        continue;
                    }
                    if (si == str_len)
                    {
                        return false;
                    }
                    if (_pattern[pindex + i] == '?' && str[si] != '.')
                    {
                        continue;
                    }
                    breakLoops = true;
                    break;
                }
                if (breakLoops)
                {
                    if (!star)
                    {
                        return false;
                    }
                    sindex++;
                    if (si == str_len)
                    {
                        return false;
                    }
                }
                else
                {
                    if (start == -1)
                    {
                        start = sindex;
                    }
                    if (pindex + i < pattern_len && _pattern[pindex + i] == '*')
                    {
                        break;
                    }
                    if (sindex + i == str_len)
                    {
                        if (end <= start)
                        {
                            end = str_len;
                        }
                        return true;
                    }
                    if (i != 0 && _pattern[pindex + i - 1] == '*')
                    {
                        return true;
                    }
                    if (!star)
                    {
                        return false;
                    }
                    sindex++;
                }
            }
            sindex += i;
            pindex += i;
            if (start == -1)
            {
                start = sindex;
            }
        }
    }
    public bool IsMatch(string str, ref int start, ref int end, char[] toLowerTable)
    {
        if (_pattern.Length == 0) return false;
        int pindex = 0;
        int sindex = 0;
        int pattern_len = _pattern.Length;
        int str_len = str.Length;
        start = -1;
        while (true)
        {
            bool star = false;
            if (_pattern[pindex] == '*')
            {
                star = true;
                do
                {
                    pindex++;
                }
                while (pindex < pattern_len && _pattern[pindex] == '*');
            }
            end = sindex;
            int i;
            while (true)
            {
                int si = 0;
                bool breakLoops = false;
                for (i = 0; pindex + i < pattern_len && _pattern[pindex + i] != '*'; i++)
                {
                    si = sindex + i;
                    if (si == str_len)
                    {
                        return false;
                    }
                    char c = toLowerTable[str[si]];
                    if (c == _pattern[pindex + i])
                    {
                        continue;
                    }
                    if (si == str_len)
                    {
                        return false;
                    }
                    if (_pattern[pindex + i] == '?' && c != '.')
                    {
                        continue;
                    }
                    breakLoops = true;
                    break;
                }
                if (breakLoops)
                {
                    if (!star)
                    {
                        return false;
                    }
                    sindex++;
                    if (si == str_len)
                    {
                        return false;
                    }
                }
                else
                {
                    if (start == -1)
                    {
                        start = sindex;
                    }
                    if (pindex + i < pattern_len && _pattern[pindex + i] == '*')
                    {
                        break;
                    }
                    if (sindex + i == str_len)
                    {
                        if (end <= start)
                        {
                            end = str_len;
                        }
                        return true;
                    }
                    if (i != 0 && _pattern[pindex + i - 1] == '*')
                    {
                        return true;
                    }
                    if (!star)
                    {
                        return false;
                    }
                    sindex++;
                    continue;
                }
            }
            sindex += i;
            pindex += i;
            if (start == -1)
            {
                start = sindex;
            }
        }
    }
}

Other episodes