Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to trim a String without allocating another one?

Tags:

string

trim

rust

I have a file in the CSV format with a first column of data that represents item code optionally ended with "UNIUNI" or mixed case of these chars, loaded by means of a barcode reader. I need to trim away the last "UNI"s.

I wrote this function:

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

The ideal function signature looks like:

fn read_csv_rilev(mut s: &String)

but probably an in-place action on a String is not a good idea. In fact, in the Rust standard library there isn't anything to do this excluding String::pop().

like image 332
robitex Avatar asked Jul 07 '15 18:07

robitex


People also ask

How do I trim string strings?

The trim() method in Java String is a built-in function that eliminates leading and trailing spaces. The Unicode value of space character is '\u0020'. The trim() method in java checks this Unicode value before and after the string, if it exists then removes the spaces and returns the omitted string.

Does trim change the string?

trim() The trim() method removes whitespace from both ends of a string and returns a new string, without modifying the original string.

How do you trim a string in C++?

The trimming string means removing whitespaces from left and right part of the string. To trim the C++ string, we will use the boost string library. In that library, there are two different methods called trim_left() and trim_right(). To trim string completely, we can use both of them.


2 Answers

Is there a way to trim a String without allocating another one?

Yes, you can use truncate to remove trailing parts of the string:

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

You don't need to mess with the allocated string at all. You can use the same logic and make successive subslices of the string. This is basically how trim_right_matches works, but a bit less generic:

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

In general, I'd probably go with the second solution.

like image 193
Shepmaster Avatar answered Sep 21 '22 22:09

Shepmaster


I know this is old, but there is a nice two liner, trim_right_matches is deprecated now, but trim_end_matches() returns a &str with the length you want

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


like image 39
storyfeet Avatar answered Sep 20 '22 22:09

storyfeet