Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find and replace every matching slice of bytes with another slice?

I have a byte vector and want to replace every [1, 2, 3] with [4, 5, 6]. How is this possible in Rust?

let mut buf = vec![1, 2, 3, 7, 8];

// ?

assert_eq!(buf, vec![4, 5, 6, 7, 8]);
like image 258
Uncreative Name Avatar asked Jan 11 '19 16:01

Uncreative Name


2 Answers

This function can do the job:

fn replace_slice<T>(source: &mut [T], from: &[T], to: &[T])
where
    T: Clone + PartialEq,
{
    let iteration = if source.starts_with(from) {
        source[..from.len()].clone_from_slice(to);
        from.len()
    } else {
        1
    };

    if source.len() > from.len() {
        replace_slice(&mut source[iteration..], from, to);
    }
}

This function is recursive but you can rewrite it using loops as well.


Example 1:

fn main() {
    let mut buf = vec![1, 2, 3, 7, 8, 1, 2, 3];

    replace_slice(&mut buf[..], &[1, 2, 3], &[4, 5, 6]);

    assert_eq!(buf, vec![4, 5, 6, 7, 8, 4, 5, 6]);
}

Playground


Example 2: (From the comment by trentcl)

fn main() {
    let mut buf = vec![1, 2, 3, 3, 4, 1, 2, 3];

    replace_slice(&mut buf[..], &[1, 2, 3], &[5, 1, 2]);

    assert_eq!(buf, vec![5, 1, 2, 3, 4, 5, 1, 2]);
}

Playground

like image 65
Ömer Erden Avatar answered Sep 19 '22 14:09

Ömer Erden


This works when the slices have different lengths (similar to replace for str):

fn replace<T>(source: &[T], from: &[T], to: &[T]) -> Vec<T>
where
    T: Clone + PartialEq
{
    let mut result = source.to_vec();
    let from_len = from.len();
    let to_len = to.len();

    let mut i = 0;
    while i + from_len <= result.len() {
        if result[i..].starts_with(from) {
            result.splice(i..i + from_len, to.iter().cloned());
            i += to_len;
        } else {
            i += 1;
        }
    }

    result
}
like image 32
burubum Avatar answered Sep 19 '22 14:09

burubum