簡體   English   中英

如何在 Rust 中從字符串的開頭“裁剪”字符?

[英]How to “crop” characters off the beginning of a string in Rust?

我想要一個函數,它可以接受兩個參數(string, number of letters to crop off front)要從(string, number of letters to crop off front)並返回相同的字符串,除了字符x之前的字母消失了。

如果我寫

let mut example = "stringofletters";
CropLetters(example, 3);
println!("{}", example);

那么輸出應該是:

ingofletters

有什么辦法可以做到這一點嗎?

在許多用途中,簡單地返回輸入的一部分是有意義的,避免任何復制。 @Shepmaster 的解決方案轉換為使用不可變切片:

fn crop_letters(s: &str, pos: usize) -> &str {
    match s.char_indices().skip(pos).next() {
        Some((pos, _)) => &s[pos..],
        None => "",
    }
}

fn main() {
    let example = "stringofletters"; // works with a String if you take a reference
    let cropped = crop_letters(example, 3);
    println!("{}", cropped);
}

與變異版本相比的優點是:

  • 不需要副本。 如果你想要一個新分配的結果,你可以調用cropped.to_string() 但你不必這樣做。
  • 它適用於靜態字符串切片以及可變String等。

缺點是,如果您確實有一個要修改的可變字符串,那么效率會稍低一些,因為您需要分配一個新的String

原始代碼的問題:

  1. 函數使用snake_case ,類型和特征使用CamelCase
  2. "foo"&str類型的字符串文字。 這些可能不會改變。 您將需要已分配給堆的內容,例如String
  3. 調用crop_letters(stringofletters, 3)會將stringofletters所有權stringofletters給該方法,這意味着您將無法再使用該變量。 您必須傳入一個可變引用 ( &mut )。
  4. Rust 字符串不是 ASCII ,它們是UTF-8 您需要弄清楚每個字符需要多少字節。 char_indices是一個很好的工具。
  5. 您需要處理字符串短於 3 個字符的情況。
  6. 一旦獲得了字符串新開頭的字節位置,就可以使用drain將一大塊字節移出字符串。 我們只是刪除這些字節,讓String移動到剩余的字節上。
fn crop_letters(s: &mut String, pos: usize) {
    match s.char_indices().nth(pos) {
        Some((pos, _)) => {
            s.drain(..pos);
        }
        None => {
            s.clear();
        }
    }
}

fn main() {
    let mut example = String::from("stringofletters");
    crop_letters(&mut example, 3);
    assert_eq!("ingofletters", example);
}

如果您實際上不需要修改原始String請參閱Chris Emerson 的回答

我找到了這個我認為不太慣用的答案:

fn crop_with_allocation(string: &str, len: usize) -> String {
    string.chars().skip(len).collect()
}

fn crop_without_allocation(string: &str, len: usize) -> &str {
    // optional length check
    if string.len() < len {
        return &"";
    }
    &string[len..]
}

fn main() {
    let example = "stringofletters"; // works with a String if you take a reference
    let cropped = crop_with_allocation(example, 3);
    println!("{}", cropped);
    let cropped = crop_without_allocation(example, 3);
    println!("{}", cropped);
}

我的版本

fn crop_str(s: &str, n: usize) -> &str {
    let mut it = s.chars();
    for _ in 0..n {
        it.next();
    }
    it.as_str()
}

#[test]
fn test_crop_str() {
    assert_eq!(crop_str("123", 1), "23");
    assert_eq!(crop_str("ЖФ1", 1), "Ф1");
    assert_eq!(crop_str("ЖФ1", 2), "1");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM