За последние 24 часа нас посетили 57808 программистов и 7256 роботов. Сейчас ищут 2145 программистов ...

Поиск последовательности одинаковых элементов массива не зная точно этих элементов

Тема в разделе "PHP для новичков", создана пользователем some_guy, 5 сен 2023.

  1. some_guy

    some_guy Новичок

    С нами с:
    5 сен 2023
    Сообщения:
    2
    Симпатии:
    1
    Файл прочитан побайтово и переведён в массив. Элементов массива много, каждый элемент string, несколько сотен тысяч. Элементами массива являются числа от 00 до FF(шестнадцатиричная система исчисления). Т.е. вот что я имею на руках:
    $massiv = array("00", "20", "07", "AD", "60", "20", "FE", "12", "20" и т.д.);
    Задача: найти в массиве последовательность элементов массива, когда я не знаю значение этих элементов, но точно знаю что: какой-то один элемент(например "20" из примера выше) повторяется сначала через три других элемента("07", "AD", "60" из примера выше), а потом повторяется через 2 других элемента("FE", "12" из примера выше).
    Т.е. в идеале я буду функцией получать номер элемента массива, с которого начинается последовательность, которую я ищу.
    Уже два года мечтаю о таком скрипте))
     
  2. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.543
    Симпатии:
    623
    Если это не массив а строка, то можно использовать регулярное выражение. Символ для подстановки в выражение можно получить из HEX с помощью функции chr:
    PHP:
    1. $char = chr(0x20);
     
  3. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Так если они должны повторяться по системе, то даже однопроходный алгоритм получается, элементарный. Идти по порядку по массиву, и смотреть
    PHP:
    1. if ($massiv[$i] == $massiv[$i +3] && $massiv[$i] == $massiv[$i + 5])
    Что-то такое, если я на ночь глядя с цифрами не ошибся.
     
  4. some_guy

    some_guy Новичок

    С нами с:
    5 сен 2023
    Сообщения:
    2
    Симпатии:
    1
    Всё здорово, получилось. Только каждое условие в отдельных скобках должно быть. И ещё и $i+4 && $i+7, т.к. текущая итерация
     
    mkramer нравится это.
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.225
    Адрес:
    там-сям
    Незачем переводить байты в массив строк. В PHP есть прекрасная функция count_chars, которая за один вызов может посчитать сколько раз встретился каждый символ.
    Например вот такой код
    PHP:
    1. $source = "a\x12\xB0.L-dc.\xB0_h.";
    2. $counts = count_count($source);
    3. var_export($counts);
    выведет такой результат:
    Код (Text):
    1. array (
    2.   18 => 1,
    3.   45 => 1,
    4.   46 => 3,
    5.   76 => 1,
    6.   95 => 1,
    7.   97 => 1,
    8.   99 => 1,
    9.   100 => 1,
    10.   104 => 1,
    11.   176 => 2,
    12. )
    если надо найти с какой позиции начинаются эти серии байтов, то добавь strpos()
    PHP:
    1. <?php
    2. $source = "a\x12\xB0.L-dc.\xB0_h.";
    3. $counts = count_chars($source, 1);
    4. $sequences = array_map(
    5.   fn ($i) => sprintf('The byte 0x%02X appears %d time(s), starting from position %d', $i, $counts[$i], strpos($source, chr($i))),
    6.   array_keys($counts)
    7. );
    8. echo implode("\n", $sequences);
    The byte 0x12 appears 1 time(s), starting from position 1
    ...
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.225
    Адрес:
    там-сям
    Или так:
    PHP:
    1. <?php
    2. $source = "\x07\x00\x20\x07\xAD\x60\x20\xFE\x12\x20";
    3. $counts = count_chars($source, 1);
    4. $sequences = [];
    5. foreach (array_keys($counts) as $i) {
    6.   $positions = [];
    7.   for ($j = 0, $p = -1; $j < $counts[$i]; $j++) {
    8.     $p = strpos($source, chr($i), $p + 1);
    9.     $positions[] = $p;
    10.   }
    11.   $sequences[] = sprintf('The byte 0x%02X appears %d times: at %s', $i, $counts[$i], implode(', ', $positions));
    12. }
    13. echo implode("\n", $sequences);
    Код (Text):
    1.  
    2. The byte 0x00 appears 1 times: at 1
    3. The byte 0x07 appears 2 times: at 0, 3
    4. The byte 0x12 appears 1 times: at 8
    5. The byte 0x20 appears 3 times: at 2, 6, 9
    6. The byte 0x60 appears 1 times: at 5
    7. The byte 0xAD appears 1 times: at 4
    8. The byte 0xFE appears 1 times: at 7
     
  7. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    @artoodetoo Ему же надо проверить повторение по системе (когда первое повторение через 3 байта, а второе - через 5). Хотя да, можно и просто со строкой это сделать
     
  8. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.225
    Адрес:
    там-сям
    я понимаю Поиск последовательности одинаковых элементов массива
    как поиск последовательности одинаковых элементов массива )) но возможно я не прав
    --- Добавлено ---
    но даже если конечная цель это нахождение известных паттернов в размещении, то скрипт мог бы проделать эту предварительную работу. будет всего навсего <= 256 цепочек для анализа
    --- Добавлено ---
    сразу после count_count() можно отбросить заведомо неподходящие варианты и сканировать остальные.