【问题标题】:c# string comparison method returning index of first non matchc#字符串比较方法返回第一个不匹配的索引
【发布时间】:2012-01-20 05:09:24
【问题描述】:

是否有一个现有的字符串比较方法会根据两个字符串之间第一次出现的不匹配字符返回一个值?

string A = "1234567890"

string B = "1234567880"

我想返回一个值,让我看到匹配中断的第一次出现是 A[8]

【问题讨论】:

  • 滚动你自己的方法不可能(也许)是一种扩展方法?
  • +1 用于首先检查它是否已经存在于标准库中。
  • 完全。当你意识到它从 1.1 开始就在框架中时,没有什么比打磨一个非常好的实现的自豪感更糟糕的了!

标签: c# string-matching


【解决方案1】:
/// <summary>
/// Gets a first different char occurence index
/// </summary>
/// <param name="a">First string</param>
/// <param name="b">Second string</param>
/// <param name="handleLengthDifference">
/// If true will return index of first occurence even strings are of different length
/// and same-length parts are equals otherwise -1
/// </param>
/// <returns>
/// Returns first difference index or -1 if no difference is found
/// </returns>
public int GetFirstBreakIndex(string a, string b, bool handleLengthDifference)
{
    int equalsReturnCode = -1;
    if (String.IsNullOrEmpty(a) || String.IsNullOrEmpty(b))
    {
        return handleLengthDifference ? 0 : equalsReturnCode;
    }

    string longest = b.Length > a.Length ? b : a;
    string shorten = b.Length > a.Length ? a : b;    
    for (int i = 0; i < shorten.Length; i++)
    {
        if (shorten[i] != longest[i])
        {
            return i;
        }
    }

    // Handles cases when length is different (a="1234", b="123")
    // index=3 would be returned for this case
    // If you do not need such behaviour - just remove this
    if (handleLengthDifference && a.Length != b.Length)
    {
        return shorten.Length;
    }

    return equalsReturnCode;
}

【讨论】:

  • 你检查a.Equals(b)而不是a == b有什么原因吗?如果a 为空,您的代码将中断。
  • 对 equals 的调用将迭代整个字符串,直到第一次中断,除非出现快捷方式,然后再迭代整个字符串。我会调用ReferenceEquals 作为捷径,但忽略Equals 的其余部分,因为无论如何它的工作都会重复。
  • 现在“abc”等于空?或者使用建议的替代方法,null 不匹配 null 的第一个字符?
  • @Jon :现在 null 被视为零长度字符串,因此当启用 handleLengthDifference 时可以将其作为 0 索引处的差异处理
  • 如果a等于b,那么它返回-1并且必须返回a或b的长度,不是吗?
【解决方案2】:

如果您安装了 .net 4.0,这可能是一种方法:

    string A = "1234567890";
    string B = "1234567880";

    char? firstocurrence = A.Zip(B, (p, q) => new { A = p, B = q })
        .Where(p => p.A != p.B)
        .Select(p => p.A)
        .FirstOrDefault();

编辑:

不过,如果你需要这个职位:

    int? firstocurrence = A.Zip(B, (p, q) => new { A = p, B = q })
            .Select((p, i) => new { A = p.A, B = p.B, idx = i })
            .Where(p => p.A != p.B)
            .Select(p => p.idx)
            .FirstOrDefault();

【讨论】:

  • 这不是问题中的要求。无论如何,如果两个字符串的长度不同,那么之后很容易检查
  • 并非如此,因为要找到“abc123432343234”与“abcdefghijk”不匹配的位置,需要您首先做一些可以回答问题的事情。
  • LINQ 不正确,由于 Where 子句,它总是返回位置 0。 Zip 之后的对应结尾是: .Select((x, idx) => (item: x, idx)).Where(x => x.item.expected != x.item.actual).Select(x => x.idx).FirstOrDefault();
【解决方案3】:

下面的扩展方法可以完成这项工作:

public static int Your_Name_Here(this string s, string other) 
{
    string first = s.Length < other.Length ? s : other;
    string second = s.Length > other.Length ? s : other;

    for (int counter = 0; counter < first.Length; counter++)
    {
        if (first[counter] != second[counter])
        {
            return counter;
        }
    }
    return -1;
}

【讨论】:

  • 如果others 短会怎样?
  • 它爆炸 :) 公平评论,将修改
  • 名字很糟糕 - 喜欢下面来自@sll的答案
  • 如果较长的字符串以较短的字符串开头,则返回 false -1。 "abc" 与字符 3 上的 "abcdef" 不匹配(字符 "abc" 根本没有),但这将返回 -1 表示匹配。
  • 这个答案应该在几年前就被删除了。如果字符串不同,但长度相同,那么firstsecond都会赋值给s,返回值为-1。
【解决方案4】:

我不知道,但这很简单:

public static int FirstUnmatchedIndex(this string x, string y)
{
  if(x == null || y == null)
    throw new ArgumentNullException();
  int count = x.Length;
  if(count > y.Length)
    return FirstUnmatchedIndex(y, x);
  if(ReferenceEquals(x, y))
    return -1;
  for(idx = 0; idx != count; ++idx)
    if(x[idx] != y[idx])
      return idx;
  return count == y.Length? -1 : count;
}

这是一个简单的序数比较。不区分大小写的序数比较是一个简单的改变,但是文化基础很难定义; “Weißbier”在第二个字符串的最后一个 S 上与“WEISSBIERS”不匹配,但这算作第 8 位还是第 9 位?

【讨论】:

  • 嘿......我们都这样做......所以应该集成一个在线编译器;)
  • @Oded 称其为“微不足道”。嗯,确实如此,但每个答案的初稿仍然存在缺陷。
【解决方案5】:

本主题与Comparing strings and get the first place where they vary from eachother 重复,其中包含使用Linq 的更好的单行解决方案

【讨论】:

    【解决方案6】:

    可以写出像

    这样的字符串扩展
    public static class MyExtensions
    {
        public static IList<char> Mismatch(this string str1, string str2)
        {
            var char1 = str1.ToCharArray();
            var char2 = str2.ToCharArray();
            IList<Char> Resultchar= new List<char>();
            for (int i = 0; i < char2.Length;i++ )
            {
                if (i >= char1.Length || char1[i] != char2[i])
                    Resultchar.Add(char2[i]);
            }
            return Resultchar;
        }
    }
    

    像这样使用它

    var r = "1234567890".Mismatch("1234567880");
    

    这不是查找不匹配的优化算法。

    如果您只想找到第一个不匹配项,

    public static Char FirstMismatch(this string str1, string str2)
            {
                var char1 = str1.ToCharArray();
                var char2 = str2.ToCharArray();             
                for (int i = 0; i < char2.Length;i++ )
                {
                    if (i >= char1.Length || char1[i] != char2[i])
                        return char2[i];
                }
                return ''c;
            }
    

    【讨论】:

      猜你喜欢
      • 2020-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多