Как найти подпоследовательность в & [u8] срезе?

У меня есть кусок &[u8] над двоичным буфером. Мне нужно разобрать его, но многие методы, которые я хотел бы использовать (например, str::find), по-видимому, не доступны на срезах.

Я видел, что я могу скрывать как срез буфера, так и свой шаблон до str, используя from_utf8_unchecked(), но это кажется немного опасным (а также действительно взломанным).

Как найти подпоследовательность в этом фрагменте? Мне действительно нужен индекс паттерна, а не только фрагмент изображения, поэтому я не думаю, что split будет работать.

Ответы

Ответ 1

Здесь простая реализация, основанная на итераторе windows.

fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
    haystack.windows(needle.len()).position(|window| window == needle)
}

fn main() {
    assert_eq!(find_subsequence(b"qwertyuiop", b"tyu"), Some(4));
    assert_eq!(find_subsequence(b"qwertyuiop", b"asd"), None);
}

Функция find_subsequence также может быть сделана общей:

fn find_subsequence<T>(haystack: &[T], needle: &[T]) -> Option<usize>
    where for<'a> &'a [T]: PartialEq
{
    haystack.windows(needle.len()).position(|window| window == needle)
}

Ответ 2

Я не думаю, что стандартная библиотека содержит функцию для этого. У некоторых libcs есть memmem, но в данный момент ящик libc не переносит это. twoway менее, вы можете использовать twoway ящик. rust-bio реализует некоторые алгоритмы сопоставления с образцом. Все это должно быть быстрее, чем использование haystack.windows(..).position(..)

Ответ 3

Как насчет Regex на байтах? Это выглядит очень мощно. Посмотрите эту демоверсию ржавой игровой площадки.

use regex::bytes::Regex;

// This shows how to find all null-terminated strings in a slice of bytes
let re = Regex::new(r"(?-u)(?P<cstr>[^\x00]+)\x00").unwrap();
let text = b"foo\x00bar\x00baz\x00";

// Extract all of the strings without the null terminator from each match.
// The unwrap is OK here since a match requires the 'cstr' capture to match.
let cstrs: Vec<&[u8]> =
    re.captures_iter(text)
      .map(|c| c.name("cstr").unwrap().as_bytes())
      .collect();
assert_eq!(vec![&b"foo"[..], &b"bar"[..], &b"baz"[..]], cstrs);

Ответ 4

Я нашел memmem Crate для этой задачи:

use memmem::{Searcher, TwoWaySearcher};

let search = TwoWaySearcher::new("dog".as_bytes());
assert_eq!(
    search.search_in("The quick brown fox jumped over the lazy dog.".as_bytes()),
    Some(41)
);