2

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;
    }
Community
  • 1
  • 1
David Fields
  • 157
  • 8
  • Just to clarify: for example, if you have `haystack` `0, 1, 1, 1, 1, 5, 6, 7, 8` and your `needle` is `1` would you return `1` or `4` as index position? And if your `needle` is `1 5`, would you return index `4`, `5`, or would you return `-1` (not found)? And lastly, if your `needle` is `5 1`, would you return `4`, `5`, or would you return `-1` (not found)? – Ian Jan 22 '16 at 06:47
  • @Ian I need it to return to 4 then 3 and so on in that order. – David Fields Jan 22 '16 at 07:41
  • I see, and what happened if you have `haystack` `1 2 1 2 1 2`? if your needle is `1 2`, would you return 4 then 2 **then 0** (note that I bold it)? or, you would read from backwards `2 1 2 1 2 1` and thus the last one will lack of `2` and you will only return 4 then 2? – Ian Jan 22 '16 at 07:44
  • @Ian `haystack` `0 1 0 0 1 1 0` `needle 1` I need it to find the numbers in this order: 5, 4, 1. Then the next index will be -1 to restart. I'm simply trying to make the code reverse its searching.. I'll appreciate an answer. Thanks. – David Fields Jan 22 '16 at 08:02
  • I got it pretty much and I was about to help, but I just wondered why you use `byte[]` in your `needle` instead of `byte` if you only can have 1 `byte`. That's why I keep giving examples of multiple bytes as `needle`. So, will your `needle` only be 1 `byte`? can it be multiple bytes? – Ian Jan 22 '16 at 08:04

2 Answers2

2

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
Ian
  • 30,182
  • 19
  • 69
  • 107
  • The code that you made is working, but I need it to search a lot faster. The original code from this question is fast enough for what I'm doing, but can you convert it to go reverse and search as fast as the original code i posted in this question? – David Fields Jan 23 '16 at 09:55
  • @JohnSmith I think that belongs to another question already... :/ probably there are some who can help you make faster algorithm in the code review. But there might be some who can do it in SO as well. Try to post it as new (separate) question with your updated code. – Ian Jan 23 '16 at 10:10
1

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();
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • How would I use your answer to call it? – David Fields Jan 22 '16 at 10:47
  • Somewhat yes, I still need to know how to use it. Example: `indexPos = SearchBytes(input, find); indexPos += find.Length;` – David Fields Jan 22 '16 at 11:07
  • It produces an `IEnumerable` which you can consume in a `foreach` or turn it to a list with `.ToList()`. How do you need to use it? – Enigmativity Jan 22 '16 at 11:12
  • I need it to give me an `int` value so I can get my search index for a byte array. Can you make that function? – David Fields Jan 22 '16 at 11:19
  • In your question you asked for it to return `11, 6, 1`. Do you want it to return the `.First()` value, or the `.Last()` value or the `.ElementAt(n)` value? – Enigmativity Jan 22 '16 at 13:06
  • I need `SearchBytes(input, find, indexPos);` to be put into a function so I can use `indexPos` to verify my placement in the byte array. – David Fields Jan 22 '16 at 22:40
  • @JohnSmith - I'm sorry, but I still have trouble understanding how you intend to use this. I don't know what you mean by "verify my placement in the byte array". Can you post some code showing how you verify the placement given a single `indexPos` please? – Enigmativity Jan 22 '16 at 23:01
  • 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;` – David Fields Jan 22 '16 at 23:25
  • @JohnSmith - Why are you doing the `indexPos += find.Length;`? What are you expecting to then do with `IndexPos`? – Enigmativity Jan 22 '16 at 23:30
  • @JohnSmith - I just had a thought. Are you doing the `indexPos += find.Length;` so that you can call `SearchBytes(input, find, indexPos);` to find the next occurrence of the needle? If that's right you don't need to. My code finds all of the `indexPos` in one go. – Enigmativity Jan 22 '16 at 23:46
  • The code that you made is working, but I need it to search a lot faster. The original code from this question is fast enough for what I'm doing, but can you convert it to go reverse and search as fast as the original code i posted in this question? – David Fields Jan 23 '16 at 09:55
  • @JohnSmith - Why is reverse faster? – Enigmativity Jan 23 '16 at 10:33
  • I just answered my own question, thanks though I will update it in this question soon. – David Fields Jan 23 '16 at 11:06