有没有一种方法可以修剪字符串而不需要分配另一个字符串?

26

我有一个以CSV格式存在的文件,它的第一列数据表示商品代码,可选末尾是 "UNIUNI" 或大小写混合的这些字符,通过条形码读取器载入。我需要去除最后的"UNI"

我写了这个函数:

fn main() {
    // Ok: from "9846UNIUNI" to "9846"
    println!("{}", read_csv_rilev("9846UNIUNI".to_string()));
    
    // Wrong: from "9846uniuni" to "9846"
    println!("{}", read_csv_rilev("9846uniuni".to_string()));
}

fn read_csv_rilev(code: String) -> String {
    code
        //.to_uppercase() /*Unstable feature in Rust 1.1*/
        .trim_right_matches("UNI")
        .to_string()
}

理想的函数签名应该像这样:

fn read_csv_rilev(mut s: &String)

但是对一个 String 进行就地操作可能不是一个好主意。实际上,在 Rust 标准库中没有任何除 String::pop() 之外的方法可以这样做。


2
.trim_right_matches() 在 Rust 1.2 中将会稳定。 - bluss
而且.trim_right()可以让您在不使用.to_string()的情况下完成此操作。只需使用修剪后的字符串的长度来进行截断即可。 - bluss
4个回答

16

有没有一种方法可以在不分配另一个字符串的情况下修剪字符串?

是的,您可以使用 truncate 来删除字符串的尾部部分:

const TRAILER: &'static str = "UNI";

fn read_csv_rilev(s: &mut String) {
    while s.ends_with(TRAILER) {
        let len = s.len();
        let new_len = len.saturating_sub(TRAILER.len());
        s.truncate(new_len);
    }
}

fn main() {
    let mut code = "Hello WorldUNIUNIUNI".into();
    
    read_csv_rilev(&mut code);
    
    assert_eq!("Hello World", code);
}

您无需对分配的字符串进行任何操作。您可以使用相同的逻辑并对字符串进行连续的子切片。这基本上就是trim_right_matches的工作原理,但比较简单:
const TRAILER: &'static str = "UNI";

fn read_csv_rilev(mut s: &str) -> &str {
    while s.ends_with(TRAILER) {
        let len = s.len();
        let new_len = len.saturating_sub(TRAILER.len());
        s = &s[..new_len];
    }
    s
}

fn main() {
    let code = "Hello WorldUNIUNIUNI";

    let truncated = read_csv_rilev(code);

    assert_eq!("Hello World", truncated);
}

总的来说,我可能会选择第二种解决方案。

6

我知道这已经过时了,但有一个好的两行代码:trim_right_matches 现在已弃用,但 trim_end_matches() 会返回你想要的 &str 长度。

fn read_csv_rilev(code: &mut String) {
        // code.to_uppercase();
        let l = code.trim_end_matches("UNI").len();
        code.truncate(l);
}



3

但是对字符串进行就地操作可能不是一个好主意。

mut s: &String 中的绑定是可变的,而不是字符串本身。如果想要改变字符串本身,可以使用 s: &mut String

话虽如此,我认为标准库中没有任何用于执行这个操作的函数。


谢谢你,Steve。你是正确的。有时候键盘上的手并没有很好地连接起来... :-) - robitex

2

另一种解决方案是使用owning_ref crate,它可以让你同时返回&str和其支持的String

extern crate owning_ref;
use owning_ref::StringRef;

fn read_csv_rilev(code: String) -> StringRef {
    StringRef::new(code).map(|s| s.trim_right_matches("UNI"))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接