2010-12-09 4 views
0

Si j'ai deux valeurs, par exemple/ABC001 et ABC100 ou A0B0C1 et A1B0C0, existe-t-il un RegEx que je peux utiliser pour m'assurer que les deux valeurs ont le même modèle?Comparer deux valeurs en utilisant RegEx

+2

Pouvez-vous nous donner plus d'exemples ou expliquer le modèle mieux? – JaredPar

+1

Connaissez-vous le modèle à l'avance? Le motif est-il constant? Ou voulez-vous être en mesure de les faire correspondre, si elles sont le même "modèle", même si vous n'avez pas vu ce modèle avant? –

+2

Qu'est-ce qui définit le "même modèle"? Voulez-vous dire qu'ils ont un chiffre aux endroits d'échantillon dans les deux chaînes, et des lettres aux mêmes endroits dans les deux chaînes? AA1 a donc le même "pattern" que "AA0" mais pas "A1A"? Un peu plus de clarification serait utile. – Donut

Répondre

2

Eh bien, il c'est mon coup de feu. Cela ne veut pas utiliser des expressions régulières, et suppose s1 et s2 ne contiennent que des chiffres ou des chiffres:

public static bool SamePattern(string s1, string s2) 
{ 
    if (s1.Length == s2.Length) 
    { 
     char[] chars1 = s1.ToCharArray(); 
     char[] chars2 = s2.ToCharArray(); 

     for (int i = 0; i < chars1.Length; i++) 
     { 
     if (!Char.IsDigit(chars1[i]) && chars1[i] != chars2[i]) 
     { 
      return false; 
     } 
     else if (Char.IsDigit(chars1[i]) != Char.IsDigit(chars2[i])) 
     { 
      return false; 
     } 
     } 

     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 

Une description de l'algorithme est la suivante:

  1. Si les chaînes ont des longueurs différentes, le retour false .
  2. Sinon, vérifiez les caractères dans la même position dans les deux chaînes:
    1. Si elles sont à la fois des chiffres ou les deux chiffres, passer à la prochaine itération.
    2. S'il ne s'agit pas de chiffres mais qu'ils ne sont pas identiques, renvoyez false.
    3. Si l'un est un chiffre et l'autre un nombre, renvoyer false.
  3. Si tous les caractères des deux chaînes ont été vérifiés avec succès, renvoyez true.
+0

Le problème est si vous testez SamePattern ("EFG001", "ABC002"); le résultat est vrai mais je veux qu'il retourne false car les lettres sont différentes – Jon

+0

@jon string1 == string2; Je pense que nous avons besoin d'une description plus détaillée de vos règles de ce qu'est un modèle correspondant. Est-ce que les lettres doivent être identiques, mais les chiffres peuvent changer? –

+0

Les lettres doivent être identiques mais les chiffres peuvent changer. J'ai le sentiment que je ne peux pas voir le bois pour les arbres. – Jon

2

Si vous ne connaissez pas le modèle à l'avance, mais allez seulement à rencontrer deux groupes de caractères (alpha et chiffres), vous pouvez effectuer les opérations suivantes:

Ecrire une C# qui analysait le premier motif , en regardant chaque caractère et déterminer si c'est alpha, ou chiffre, puis générer une regex en conséquence de ce modèle.

Vous pouvez trouver qu'il n'y a pas de code d'écriture de point pour générer une regex, car il pourrait être tout aussi simple de vérifier la deuxième chaîne par rapport à la première.

Alternativement, sans regex:

Vérifiez d'abord les chaînes sont de la même longueur. Parcourez ensuite les deux chaînes en même temps, char par char. Si char [x] de la chaîne 1 est alpha, et char [x] de la chaîne deux est la même, vos modèles sont correspondants. Essayez ceci, il devrait faire face si une chaîne se faufile dans certains symboles. Edité pour comparer les valeurs caractère ... et utiliser Char.IsLetter et Char.IsDigit

private bool matchPattern(string string1, string string2) 
{ 
    bool result = (string1.Length == string2.Length); 
    char[] chars1 = string1.ToCharArray(); 
    char[] chars2 = string2.ToCharArray(); 

    for (int i = 0; i < string1.Length; i++) 
    { 
     if (Char.IsLetter(chars1[i]) != Char.IsLetter(chars2[i])) 
     { 
      result = false; 
     } 
     if (Char.IsLetter(chars1[i]) && (chars1[i] != chars2[i])) 
     { 
      //Characters must be identical 
      result = false; 
     } 
     if (Char.IsDigit(chars1[i]) != Char.IsDigit(chars2[i])) 
      result = false; 
    } 
    return result; 
} 
1

Pensez à utiliser Char.GetUnicodeCategory
Vous pouvez écrire une classe d'aide pour cette tâche:

public class Mask 
{ 
    public Mask(string originalString) 
    { 
     OriginalString = originalString; 
     CharCategories = originalString.Select(Char.GetUnicodeCategory).ToList(); 
    } 

    public string OriginalString { get; private set; } 
    public IEnumerable<UnicodeCategory> CharCategories { get; private set; } 

    public bool HasSameCharCategories(Mask other) 
    { 
     //null checks 
     return CharCategories.SequenceEqual(other.CharCategories); 
    } 
} 

Utiliser comme

Mask mask1 = new Mask("ab12c3"); 
Mask mask2 = new Mask("ds124d"); 
MessageBox.Show(mask1.HasSameCharCategories(mask2).ToString()); 
+0

Je n'ai pas exécuté ceci mais je m'attendrais à ce que le résultat soit faux car même si le motif correspond aux lettres utilisées, elles sont différentes. – Jon

+0

+1 pour GetUnicodeCategory, bien que j'avoue avoir trouvé le code difficile à suivre, je pense que l'ajout d'un peu de typage explicite aiderait? Comme List CharCategories –

+0

@Jon - que j'ai mal compris votre question, et peut supprimer la réponse rapidement. Donc 'AA0' et' AA1' sont les mêmes, mais 'AA0' et' BB0' ne le sont pas? – Kobi

0

Je ne sais pas la syntaxe C#, mais voici un code pseudo:

  • divisé les cordes sur ''
  • sorte les 2 tableaux
  • rejoignent les tableaux avec ''
  • comparer les 2 chaînes
0

Une solution polyvalente avec LINQ peut être obtenue assez facilement. L'idée est:

  1. Trier les deux chaînes (réorganisation des caractères).
  2. Comparez chaque chaîne triée en tant que séquence de caractères en utilisant SequenceEquals.

Ce schéma permet à une courte solution élégante et configurable, par exemple:

// We will be using this in SequenceEquals 
class MyComparer : IEqualityComparer<char> 
{ 
    public bool Equals(char x, char y) 
    { 
     return x.Equals(y); 
    } 

    public int GetHashCode(char obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

// and then: 
var s1 = "ABC0102"; 
var s2 = "AC201B0"; 

Func<char, double> orderFunction = char.GetNumericValue; 
var comparer = new MyComparer(); 
var result = s1.OrderBy(orderFunction).SequenceEqual(s2.OrderBy(orderFunction), comparer); 

Console.WriteLine("result = " + result); 

Comme vous pouvez le voir, il est dans 3 lignes de code (sans compter la classe) comparateur. C'est aussi très très facilement configurable.

  • Le code tel qu'il est vérifie si s1 est une permutation de s2.
  • Voulez-vous vérifier si s1 a le même nombre et le même type de caractères avec s2, mais pas nécessairement les mêmes caractères (par exemple "ABC" pour être égal à "ABB")? Pas de problème, remplacez MyComparer.Equals par return char.GetUnicodeCategory(x).Equals(char.GetUnicodeCategory(y));.
  • En modifiant les valeurs orderFunction et comparer, vous pouvez configurer une multitude d'autres options de comparaison.

Et enfin, puisque je ne trouve pas très élégant de définir une classe MyComparer juste pour permettre à ce scénario, vous pouvez également utiliser la technique décrite dans cette question:

Wrap a delegate in an IEqualityComparer

à définissez votre comparateur comme un lambda en ligne. Cela aboutirait à une solution configurable contenue dans 2-3 lignes de code.

Questions connexes