web-dev-qa-db-fra.com

Existe-t-il une méthode comme celle de JavaScript dans Rust?

J'ai jeté un œil à Rust docs pour String mais je ne trouve pas le moyen d'extraire une sous-chaîne.

Existe-t-il une méthode comme substr de JavaScript dans Rust? Sinon, comment le mettriez-vous en œuvre?

str.substr(start[, length])

Le plus proche est probablement slice_unchecked mais il utilise des décalages d'octets au lieu d'index de caractères et est marqué unsafe.

15
laktak

Pour les personnages, vous pouvez utiliser s.chars().skip(pos).take(len):

fn main() {
    let s = "Hello, world!";
    let ss: String = s.chars().skip(7).take(5).collect();
    println!("{}", ss);
}

Attention cependant à la définition des caractères Unicode.

Pour les octets, vous pouvez utiliser la syntaxe slice:

fn main() {
    let s = "Hello, world!";
    let ss = &s[7..12];
    println!("{}", ss);
}
27
WiSaGaN

Vous pouvez utiliser la méthode as_str sur l'itérateur Chars pour récupérer une tranche &str après l'avoir remplacé. Donc, pour sauter les premiers caractères start, vous pouvez appeler

let s = "Some text to slice into";
let mut iter = s.chars();
iter.by_ref().nth(start); // eat up start values
let slice = iter.as_str(); // get back a slice of the rest of the iterator

Maintenant, si vous voulez aussi limiter la longueur, vous devez d'abord déterminer la position d'octet du caractère length:

let end_pos = slice.char_indices().nth(length).map(|(n, _)| n).unwrap_or(0);
let substr = &slice[..end_pos];

Cela peut sembler un peu détourné, mais Rust ne vous cache rien qui puisse prendre des cycles de processeur. Cela dit, je me demande pourquoi il n’ya pas encore de caisse qui offre une méthode substr.

10
oli_obk

Pour la syntaxe de type my_string.substring(start, len)-, vous pouvez écrire un trait personnalisé:

trait StringUtils {
    fn substring(&self, start: usize, len: usize) -> Self;
}

impl StringUtils for String {
    fn substring(&self, start: usize, len: usize) -> Self {
        self.chars().skip(start).take(len).collect()
    }
}

// Usage:
fn main() {
    let phrase: String = "this is a string".to_string();
    println!("{}", phrase.substring(5, 8)); // prints "is a str"
}
3
user1656730

Ce code effectue à la fois une sous-chaîne et une division en chaîne, sans paniquer ni allouer:

use std::ops::{Bound, RangeBounds};

trait StringUtils {
    fn substring(&self, start: usize, len: usize) -> &str;
    fn slice(&self, range: impl RangeBounds<usize>) -> &str;
}

impl StringUtils for str {
    fn substring(&self, start: usize, len: usize) -> &str {
        let mut char_pos = 0;
        let mut byte_start = 0;
        let mut it = self.chars();
        loop {
            if char_pos == start { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_start += c.len_utf8();
            }
            else { break; }
        }
        char_pos = 0;
        let mut byte_end = byte_start;
        loop {
            if char_pos == len { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_end += c.len_utf8();
            }
            else { break; }
        }
        &self[byte_start..byte_end]
    }
    fn slice(&self, range: impl RangeBounds<usize>) -> &str {
        let start = match range.start_bound() {
            Bound::Included(bound) | Bound::Excluded(bound) => *bound,
            Bound::Unbounded => 0,
        };
        let len = match range.end_bound() {
            Bound::Included(bound) => *bound + 1,
            Bound::Excluded(bound) => *bound,
            Bound::Unbounded => self.len(),
        } - start;
        self.substring(start, len)
    }
}

fn main() {
    let s = "abcdèfghij";
    // All three statements should print:
    // "abcdè, abcdèfghij, dèfgh, dèfghij."
    println!("{}, {}, {}, {}.",
        s.substring(0, 5),
        s.substring(0, 50),
        s.substring(3, 5),
        s.substring(3, 50));
    println!("{}, {}, {}, {}.",
        s.slice(..5),
        s.slice(..50),
        s.slice(3..8),
        s.slice(3..));
    println!("{}, {}, {}, {}.",
        s.slice(..=4),
        s.slice(..=49),
        s.slice(3..=7),
        s.slice(3..));
}
0
carlo.milanesi