在大字符数组C#中查找小字符数组

时间:2014-02-07 20:14:46

标签: c# char arrays

假设我有一个包含数千个项目的大字符数组:

char[] mobyDick = "..."mobyDick.Length = 2000。

我想知道该数组中是否存在某个字符数组,其中*是*。 (更新:我真的只需要知道它是否在主阵列中的某个索引之后。)

char[] test = {'a','b','c','d'}

我可以做类似

的事情
char[] mobyDick = "..."
string mobyString = new string(mobyDick);
if (mobyString.Contains(new string(test)))
{ do stuff}

但这对我的情况来说不是最佳的,因为我正在尝试编写一个必须非常快速地工作的解析器,而且我不想每个字母左右创建和搜索字符串。

是否有某种方式(通过算法或通过某种.Net方法)找出mobyDick作为char数组是否包含abcd作为char数组?

7 个答案:

答案 0 :(得分:2)

这看起来像一个有趣的问题,所以我开始创建一个扩展方法......

 public static class ExtensionMethods
{
    public static int ContainsArray(this char[] arrayToSearchIn, char[] arrayToFind)
    {
        if (arrayToFind.Length == 0)
            return -1;

        int lengthOfArrayToFInd = arrayToFind.Length;
        int lengthOfArrayToSearchIn = arrayToSearchIn.Length;
        for (int i = 0; i < lengthOfArrayToSearchIn; i++)
        {
            if (lengthOfArrayToSearchIn - i < lengthOfArrayToFInd)
                return -1;

            if (arrayToSearchIn[i] != arrayToFind[0])
                continue;

            int arrayToFindCounter = 0;
            bool wasFound = true;
            for (int j = i; j < i + lengthOfArrayToFInd; j++)
            {
                if (arrayToFind[arrayToFindCounter] == arrayToSearchIn[j])
                    arrayToFindCounter++;
                else
                {
                    wasFound = false;
                    break;
                }
            }

            if (wasFound)
                return i;
        }

        return -1;
    }

}

这对我来说是使用任何长度子数组,包括空搜索 - 如果找到则返回第一个匹配的位置(从零开始),否则返回-1。

示例用法:

 static void Main(string[] args)
    {
        //                        0    1    2    3    4    5    6    7    8    9    0    1    2    3    4    5    6    7    8  
        char[] mobyDick = new[] {'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'd', 'a', 'z', 'y'};
        char[] test = {'a', 'b', 'c', 'd'};

        Console.WriteLine(mobyDick.ContainsArray(test));  // Position 12

        Console.ReadLine();
    }

答案 1 :(得分:1)

尝试一下:

private bool Contains(char[] mobyDick, char[] test)
{
    for (int i = 0; i < mobyDick.Length - test.Length + 1; i++)
    {
        bool found = true;

        for (int j = 0; j < test.Length; j++)
        {
            if (mobyDick[i + j] != test[j])
            {
                found = false;
                break;
            }
        }

        if (found) return true;
    }

    return false;
}

答案 2 :(得分:1)

我会尝试这种扩展方法:

public static bool ContainsChars(this char[] source, char[] target,out int index)
{
     int targetLength = target.Length - 1;
     int count = 0;
     char currentCharToSearch = target[0];
     for(int i=0; i<source.Length; i++)
     {
          if (source[i] == currentCharToSearch)
          {
              count++;
              if (count == targetLength) 
              {
                  index = i - count + 1;
                  return true;
              }
              else
              {
                  currentCharToSearch = target[count];
              }
           }
           else
           {
               count = 0;
               currentCharToSearch = target[0];
           }
      }
      index = -1;
      return false;
}

用法:

var c1 = new char[] { 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'h', 't' };
var c2 = new char[] { 'c', 'h', 't' };

int index;
var result = c1.ContainsChars(c2,out index); // true index = 6

c2 = new char[] { 'c', 't', 'h' };
var result2 = c1.ContainsChars(c2,out index); // false index = -1

答案 3 :(得分:1)

这是一个使用lambda查找搜索的所有有效“起点”的人。

//return first index of substring or -1 for not found
int searchForChar(char [] substring, char [] fulltext)
{
    //all of the start points
    var indices = fulltext.Select ((b,i) => b == substring.FirstOrDefault() ? i : -1)
                          .Where(i => i != -1).ToArray();

    //search each start point
    foreach (var index in indices)
    {
        var found = true;
        int count = 0;
        for(int i = index; i < index + substring.Length; i++)
        {   
            found = true;
            if(substring[count++] != fulltext[i])
            {   
                found = false;
                break;
            }   
        }
        if (found) return index;
    }
    return -1;
}

可能一种更高效的方式就像你在原始问题中所做的那样。

int searchForChar(char [] substring, char [] fulltext)
{
    return fulltext.ToString().IndexOf(substring.ToString());

}

答案 4 :(得分:0)

for循环如何首先在大数组中搜索测试用例的第一个字符,然后将测试数组中的连续字符与大数组的连续成员进行比较?

答案 5 :(得分:0)

对于记录,这是使用通用扩展方法的另一种解决方案。它适用于任何实现IComparable的数组类型。

void Main()
{
    var c1 = new char[] { 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'h', 't' };
    var c2 = new char[] { 'c', 'h', 't' };

    if (c1.Contains(c2))
    {
        // do something
    }

    int i = c1.IndexOf(c2);
}

public static class ArrayExtensions
{
    public static bool Contains<T>(this T[] array, T[] subarray) where T : IComparable
    {
        return array.IndexOf(subarray) >= 0;
    }

    public static int IndexOf<T>(this T[] array, T[] subarray) where T : IComparable
    {
        for (int i = 0; i < array.Length - subarray.Length + 1; i++)
        {
            bool found = true;

            for (int j = 0; j < subarray.Length; j++)
            {
                if (array[i + j].CompareTo(subarray[j]) != 0)
                {
                    found = false;
                    break;
                }
            }

            if (found) return i;
        }

        return -1;
    }
}

答案 6 :(得分:-2)

使用此:

var search = mobyDick.Intersect(test);
if (search.ToArray().Length > 0)
{
//do something
}

LINQ - Set Operators