David Fields
David Fields

Reputation: 157

C# How to find a byte array inside a byte array going reverse?

I'm trying to find a byte array byte[] inside another byte array byte[] going reverse.

Question: How can I search a byte array inside another byte array from end to start?

This link is a reference of the code I'm making c# How to Continuously find a byte array inside a byte array?

EDIT: I need this code converted to searching for a byte arry within another byte array going reverse.

        indexPos = SearchBytes(input, find, indexPos);

        Console.WriteLine("Found at " + indexPos);

        indexPos += find.Length;

UPDATED: When I click the button, the index needs to search as follows: 11, 6 1

This code below is what I need to have searching from end to start:

byte[] input = { 0, 1, 1, 1, 5, 6, 1, 1, 1, 7, 8, 1, 1, 1 };
    byte[] find = { 1, 1, 1 };
    int indexPos = 0;

    private void button1_Click(object sender, EventArgs e)
    {
        indexPos = SearchBytes(input, find, indexPos);

        Console.WriteLine("Found at " + indexPos);

        indexPos += find.Length;
    }

    public int SearchBytes(byte[] haystack, byte[] needle, int start_index)
    {
        int len = needle.Length;
        int limit = haystack.Length - len;
        for (int i = start_index; i <= limit; i++)
        {
            int k = 0;
            for (; k < len; k++)
            {
                if (needle[k] != haystack[i + k]) break;
            }
            if (k == len) return i;
        }
        return -1;
    }

Upvotes: 2

Views: 873

Answers (2)

Enigmativity
Enigmativity

Reputation: 117029

This works for me:

byte[] input = { 0, 1, 1, 1, 5, 6, 1, 1, 1, 7, 8, 1, 1, 1 };
byte[] find = { 1, 1, 1 };

var query =
    input
        .Select((x, n) => new
        {
            n,
            found = input.Skip(n).Take(find.Length).SequenceEqual(find)
        })
        .Where(x => x.found)
        .Select(x => x.n)
        .Reverse();

I get { 11, 6, 1 }.

If I start with:

byte[] input = { 0, 1, 0, 0, 1, 1, 0, };
byte[] find = { 1, };

...then I get { 5, 4, 1 }.


Here it is as a function:

public IEnumerable<int> SearchBytes(byte[] haystack, byte[] needle)
{
    return
        haystack
            .Select((x, n) => new
            {
                n,
                found = haystack.Skip(n).Take(needle.Length).SequenceEqual(needle)
            })
            .Where(x => x.found)
            .Select(x => x.n)
            .Reverse();
}

Upvotes: 1

Ian
Ian

Reputation: 30813

You can use LINQ query as well as Array.Reverse to help you.


Edit:

To find the pattern of multiple bytes, you need to update the LINQ query like this

byte[] input = { 0, 1, 1, 1, 5, 6, 1, 1, 1, 7, 8, 1, 1, 1 };
byte[] find = { 1, 1, 1 };
int indexNow = 0;
int findLength = find.Length;
int[] indexes = (from i in input                                             
                let index = indexNow++
                where index <= input.Length - findLength //cannot exceeds this on the search
                let compared = input.Skip(index).Take(findLength)
                where Enumerable.SequenceEqual(find, compared)
                select index).Reverse().ToArray();

And the result in your indexes will be 11,6,1 as you wanted.

To use a function, simply put all the queries and inputs used above to a function returning indexes.

public int[] SearchBytes(byte[] input, byte[] find){
    int indexNow = 0;
    return (from i in input                                          
            let index = indexNow++
            where index <= input.Length - find.Length//cannot exceeds this on the search
            let compared = input.Skip(index).Take(find.Length)
            where Enumerable.SequenceEqual(find, compared)
            select index).Reverse().ToArray();    
}

Original:

Assuming you only define one byte needle as discussed in the comments, you could do it like this:

byte[] input = { 0, 1, 1, 1, 1, 5, 6, 7, 8 };
byte[] find = { 1 };
int indexNow = 0;
int[] indexes = (from i in input
                  let index = indexNow++
                  where i == find[0]                                        
                  select index).ToArray();
Array.Reverse(indexes);

And the result in your indexes will be 4,3,2,1 as you wanted.

Now if you want to search for find with multiple values:

byte[] find = { 1, 0, 5, 6 };

Then you could loop over the query:

byte[] input = { 0, 1, 1, 1, 1, 5, 6, 7, 8 };
byte[] find = { 1, 0, 5, 6 };

List<int[]> indexesList = new List<int[]>();

foreach (byte findNow in find){
    int indexNow = 0;
    int[] indexes = (from i in input
                      let index = indexNow++
                      where i == find[0]                                        
                      select index).ToArray();
    Array.Reverse(indexes);
    indexesList.Add(indexes);
}

Then all your results will be in the indexesList as follow:

4, 3, 2, 1
0
5
6

Upvotes: 2

Related Questions