web-dev-qa-db-fra.com

Faire correspondre les chaînes avec un caractère générique

Je voudrais faire correspondre les chaînes avec un caractère générique (*), le caractère générique signifiant "tout". Par exemple:

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

En outre, certaines utilisations composées telles que:

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

Y a-t-il un algorithme simple pour faire cela? Je ne suis pas sûr d'utiliser regex (bien que ce soit une possibilité).

Pour clarifier, les utilisateurs taperont ce qui précède dans une boîte à filtres (un filtre aussi simple que possible), je ne veux pas qu'ils écrivent eux-mêmes des expressions régulières. Donc, quelque chose que je peux facilement transformer de la notation ci-dessus serait bien.

50
Robinson

Juste pour votre information, vous pourriez utiliser VB.NET Like-Operator :

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

Utilisation CompareMethod.Text _ si vous voulez ignorer le cas.

Vous devez ajouter using Microsoft.VisualBasic.CompilerServices;.

22
Tim Schmelter

Souvent, les jokers fonctionnent avec deux types de jokers:

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

afin que vous puissiez facilement convertir ces règles en expressions appropriées régulières n:

  // 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("\\*", ".*") + "$"; 
  }

Et ensuite vous pouvez utiliser Regex comme d'habitude:

  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"));
106
Dmitry Bychenko

Utilisation de WildcardPattern de System.Management.Automation peut être une option.

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

L’interface utilisateur de Visual Studio peut ne pas vous permettre d’ajouter System.Management.Automation Assemblée aux références de votre projet. N'hésitez pas à l'ajouter manuellement, comme décrit ici .

15
VirtualVDX

*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$"
4
Avinash Raj

Un wildcard * peut être traduit par .* ou .*? motif de regex.

Vous devrez peut-être utiliser un mode ligne unique pour faire correspondre les symboles de nouvelle ligne. Dans ce cas, vous pouvez utiliser (?s) dans le cadre du motif regex.

Vous pouvez le définir pour tout ou partie du motif:

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

Il est nécessaire de prendre en compte le fait que Regex IsMatch donne la valeur true avec XYZ lors de la vérification de la correspondance avec Y *. Pour l'éviter, j'utilise l'ancre "^"

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

Donc, le code complet pour résoudre votre problème est

    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;
    }
3
Pavel Khrapkin