Как найти подпоследовательность в & [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)
);