【问题标题】:Compare two values using RegEx使用 RegEx 比较两个值
【发布时间】:2011-05-22 22:52:55
【问题描述】:

如果我有两个值,例如 /ABC001 和 ABC100 或 A0B0C1 和 A1B0C0,是否可以使用 RegEx 来确保这两个值具有相同的模式?

【问题讨论】:

  • 你能给我们更多的例子或者更好地解释这个模式吗?
  • 你提前知道模式吗?模式是否恒定?或者您是否希望能够匹配它们,如果它们是相同的“模式”,即使您以前没有见过那种模式?
  • 什么定义了“相同的模式”?你的意思是他们在两个字符串的样本位置都有一个数字,在两个字符串的相同位置都有字母?所以AA1AA0 具有相同的“模式”,但不是A1A?再澄清一点会很有帮助。
  • 问题是我不确定模式是什么。它可能会有所不同。我有 2 个包含字母数字字符的值,我想确保第一个值与第二个值具有相同的模式。
  • “相同模式”是什么意思?我可以想出几十种匹配这些字符串的模式。

标签: c# .net regex .net-3.5 c#-3.0


【解决方案1】:

如果您事先不知道模式,但只会遇到两组字符(字母和数字),那么您可以执行以下操作:

编写一些解析第一个模式的 C#,查看每个字符并确定它是 alpha 还是数字,然后根据该模式相应地生成一个正则表达式。

您可能会发现编写代码来生成正则表达式没有意义,因为检查第二个字符串与第一个字符串可能一样简单。

或者,没有正则表达式:

首先检查字符串的长度是否相同。 然后逐个字符地同时循环遍历两个字符串。如果字符串 1 中的 char[x] 是 alpha,并且字符串 2 中的 char[x] 相同,则说明模式匹配。

试试这个,如果字符串潜入某些符号,它应该可以应付。 编辑以比较字符值 ... 并使用 Char.IsLetter 和 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;
}

【讨论】:

    【解决方案2】:

    考虑使用Char.GetUnicodeCategory
    您可以为此任务编写一个帮助类:

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

    用作

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

    【讨论】:

    • 我没有运行这个,但我希望结果是假的,因为虽然模式匹配使用的字母不同。
    • +1 表示 GetUnicodeCategory,虽然我承认我发现代码难以理解,但我认为添加一些显式输入会有所帮助吗?如 List CharCategories
    • @Jon - 我完全误解了你的问题,可能会立即删除答案。所以AA0AA1是一样的,但是AA0BB0不一样?
    • @Andrew - 这不是我最好的作品,我看到 :) 只是一个快速演示。
    【解决方案3】:

    好吧,这是我的尝试。这不使用正则表达式,并假设s1s2 只包含数字或数字:

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

    算法说明如下:

    1. 如果字符串长度不同,返回false
    2. 否则,检查两个字符串中相同位置的字符:
      1. 如果它们都是数字或两个数字,则继续下一个迭代。
      2. 如果不是数字但不相同,则返回false
      3. 如果一个是数字,一个是数字,返回false
    3. 如果两个字符串中的所有字符都检查成功,则返回true

    【讨论】:

    • 问题是如果你测试 SamePattern("EFG001", "ABC002");结果为真,但我希望它返回假,因为字母不同
    • @jon string1 == string2;我认为我们需要更详细地描述您对匹配模式的规则。字母是否需要相同,但数字可能会改变?
    • 字母必须相同,但数字可以更改。我有一种只见树木不见林的感觉。
    • 好的,我已经更新了。这应该对你有用,SamePattern("ABC001", "ABC002") 返回 true 而 SamePattern("EFG001", "ABC002") 返回 false。
    • 如果可以,您可以使用c1 &gt;= '0'Char.IsDigit 大大提高可读性。
    【解决方案4】:

    我不知道 C# 语法,但这是一个伪代码:

    • 拆分''上的字符串
    • 对 2 个数组进行排序
    • 用 '' 连接每个数组
    • 比较两个字符串

    【讨论】:

      【解决方案5】:

      使用 LINQ 的通用解决方案可以很容易地实现。这个想法是:

      1. 对两个字符串进行排序(重新排序字符)。
      2. 使用SequenceEquals将每个已排序的字符串作为字符序列进行比较。

      此方案可实现简短、优雅且可配置的解决方案,例如:

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

      如您所见,这一切都在 3 行代码中(不包括比较器类)。它也非常容易配置。

      • 当前代码检查s1 是否是s2 的排列。
      • 是否要检查s1 是否与s2 具有相同数量和种类的字符,但不一定相同(例如“ABC”等于“ABB”)?没问题,把MyComparer.Equals改成return char.GetUnicodeCategory(x).Equals(char.GetUnicodeCategory(y));
      • 通过更改orderFunctioncomparer 的值,您可以配置许多其他比较选项。

      最后,因为我觉得定义一个MyComparer 类只是为了启用这个场景不是很优雅,你也可以使用这个问题中描述的技术:

      Wrap a delegate in an IEqualityComparer

      将您的比较器定义为内联 lambda。这将产生包含在 2-3 行代码中的可配置解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-25
        • 2012-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多