5
votes

Comment trouver et remplacer chaque tranche d'octets correspondante par une autre tranche?

J'ai un vecteur d'octets et je souhaite remplacer chaque [1, 2, 3] par [4, 5, 6] . Comment est-ce possible dans Rust?

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

// ?

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


10 commentaires

La tranche de remplacement a-t-elle nécessairement la même longueur que la tranche à remplacer? Ou pourriez-vous avoir à réduire / agrandir le Vec ?


Je ne pense pas qu'il y ait actuellement de routine générale pratique définie sur & [u8] qui le fasse pour vous, similaire à la méthode str :: replace . Je l'implémenterais probablement moi-même, éventuellement en copiant le implémentation pour str :: replace . (Je travaille sur une bibliothèque de chaînes d'octets pour Rust, qui supportera certainement des opérations comme celle-ci. Mais ce n'est pas encore fini.)


Copie possible de Comment copier idiomatiquement une tranche?


L'application de la question liée ici suggère buf [0..3] .copy_from_slice (& [4, 5, 6]); . Si les tranches ne sont pas de la même taille, il s'agit probablement d'un doublon de Insérez ou remplacez efficacement plusieurs éléments au milieu ou au début d'un Vec ? à la place


Mon erreur, j'ai oublié le mot «chaque» dans la question. Mais les liens ci-dessus sont toujours bons à regarder.


Autre question: si vous remplacez [1, 2, 3] par [5, 1, 2] dans [1, 2, 3, 3] , attendez-vous [5, 1, 2, 3] ? Les deux réponses existantes vous donneront [5, 5, 1, 2] .


@trentcl title pour les points d'interrogation: "remplacer une sous-tranche d'un octet Vec / slice par une autre tranche?" . Ce n'est pas valable pour votre deuxième cas car vous ne remplacez pas le dernier élément (" 3 ") par une autre tranche (juste en remplaçant par un élément qui provient d'un autre tranche )


@ ÖmerErden C'est ce que je veux dire . J'ai pris la fonction replace_slice directement à partir de votre réponse. Je ne m'attends pas à ce que ce comportement soit ce que souhaite OP.


@trentcl je vois, merci d'avoir mis à jour le code maintenant cela fonctionne aussi avec votre cas.


Voir aussi Comment puis-je trouver une sous-séquence dans un & [ u8] tranche? .


3 Réponses :


1
votes

Cette fonction peut faire le travail:

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]);
}

Cette fonction est récursive mais vous pouvez également la réécrire en utilisant des boucles.


Exemple 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


Exemple 2: (D'après le commentaire de trentcl)

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);
    }
}

Playground


0 commentaires

0
votes

Sans récursivité:

fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
where
    T: Clone + PartialEq,
{
    for i in 0..=buf.len() - from.len() {
        if buf[i..].starts_with(from) {
            buf[i..(i + from.len())].clone_from_slice(to);
        }
    }
}


5 commentaires

Vous pouvez envisager de changer votre boucle en ceci: for i in 0 .. = buf.len () - from.len () pour sauter les vérifications inutiles.


@ ÖmerErden source.len () - from.len () paniquera lorsque from est plus grand que source .


@trentcl merci de l'avoir signalé, il paniquera également lorsque "from" et "to" ne sont pas de taille égale, en raison d'une assertion dans "starts_with". L'ajout de gardes avant la boucle aidera.


@ ÖmerErden starts_with ne panique pas si self et aiguille sont de tailles différentes; il renvoie simplement false .


@trentcl désolé ça devrait être "clone_from_slice"



0
votes

Cela fonctionne lorsque les tranches ont des longueurs différentes (similaire à replace pour 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
}


0 commentaires