简体   繁体   English

如何在 Rust 中从字符串的开头“裁剪”字符?

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

I want a function that can take two arguments (string, number of letters to crop off front) and return the same string except with the letters before character x gone.我想要一个函数,它可以接受两个参数(string, number of letters to crop off front)要从(string, number of letters to crop off front)并返回相同的字符串,除了字符x之前的字母消失了。

If I write如果我写

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

then the output should be:那么输出应该是:

ingofletters

Is there any way I can do this?有什么办法可以做到这一点吗?

In many uses it would make sense to simply return a slice of the input, avoiding any copy.在许多用途中,简单地返回输入的一部分是有意义的,避免任何复制。 Converting @Shepmaster's solution to use immutable slices:@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);
}

Advantages over the mutating version are:与变异版本相比的优点是:

  • No copy is needed.不需要副本。 You can call cropped.to_string() if you want a newly allocated result;如果你想要一个新分配的结果,你可以调用cropped.to_string() but you don't have to.但你不必这样做。
  • It works with static string slices as well as mutable String etc.它适用于静态字符串切片以及可变String等。

The disadvantage is that if you really do have a mutable string you want to modify, it would be slightly less efficient as you'd need to allocate a new String .缺点是,如果您确实有一个要修改的可变字符串,那么效率会稍低一些,因为您需要分配一个新的String

Issues with your original code:原始代码的问题:

  1. Functions use snake_case , types and traits use CamelCase .函数使用snake_case ,类型和特征使用CamelCase
  2. "foo" is a string literal of type &str . "foo"&str类型的字符串文字。 These may not be changed.这些可能不会改变。 You will need something that has been heap-allocated, such as a String .您将需要已分配给堆的内容,例如String
  3. The call crop_letters(stringofletters, 3) would transfer ownership of stringofletters to the method, which means you wouldn't be able to use the variable anymore.调用crop_letters(stringofletters, 3)会将stringofletters所有权stringofletters给该方法,这意味着您将无法再使用该变量。 You must pass in a mutable reference ( &mut ).您必须传入一个可变引用 ( &mut )。
  4. Rust strings are not ASCII , they are UTF-8 . Rust 字符串不是 ASCII ,它们是UTF-8 You need to figure out how many bytes each character requires.您需要弄清楚每个字符需要多少字节。 char_indices is a good tool here. char_indices是一个很好的工具。
  5. You need to handle the case of when the string is shorter than 3 characters.您需要处理字符串短于 3 个字符的情况。
  6. Once you have the byte position of the new beginning of the string, you can use drain to move a chunk of bytes out of the string.一旦获得了字符串新开头的字节位置,就可以使用drain将一大块字节移出字符串。 We just drop these bytes and let the String move over the remaining bytes.我们只是删除这些字节,让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);
}

See Chris Emerson's answer if you don't actually need to modify the original String .如果您实际上不需要修改原始String请参阅Chris Emerson 的回答

I found this answer which I don't consider really idiomatic:我找到了这个我认为不太惯用的答案:

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

my version我的版本

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