Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split string and skip empty substrings

I am learning Rust and discovered this problem:

I would like to split a string by a pattern and remove all cases where the resultin substring is empty.

Here is an example:

let s = "s,o,m,e,";
for elem in s.split(",").skip_while(|&x| x.is_empty()) {
    print!(" <{}> ", elem);
    //print!(" <{}>({}) ", elem, elem.is_empty());
}

But the result is the following:

 <s>  <o>  <m>  <e>  <> 

My thoughts were: The struct Split returned by split implements Iterator which provides skip_while. IntelliSense told me the x in the closure is of type &&str so I would assume all the elements of the iterator (of type &str) which are empty to be omitted.

But it doesn't skip the empty substring.

I also tried to print the result of the is_empty function. It shows that the last slice is indeed empty. If I instead for the skip_while use skip_while(|&x| x == "s"), it correctly leaves out the "s" (printed with is_empty here):

 <o>(false)  <m>(false)  <e>(false)  <>(true)

So somehow the slice behaves differently in the iterator?

Why is that or where am I mistaken?

like image 574
Gero Avatar asked Dec 18 '22 12:12

Gero


1 Answers

If you only need to omit the 1 empty string at the end of input, just use split_terminator instead of split. This adapter is basically just like split but it treats the pattern argument as a terminator instead of a separator, so the empty string at the end of input is not considered a new element.

If you truly want to skip all the empty strings, keep reading.


skip_while is doing exactly as its documentation says (emphasis mine):

skip_while() takes a closure as an argument. It will call this closure on each element of the iterator, and ignore elements until it returns false.

After false is returned, skip_while()'s job is over, and the rest of the elements are yielded.

Filtering out all the elements that match a predicate, regardless of where they are in the sequence, is the job of filter:

let s = ",s,o,,m,e,";
for elem in s.split(",").filter(|&x| !x.is_empty()) {
    print!(" <{}> ", elem);
}

The above code will have the effect you wanted.

Note that the predicate to filter has the opposite meaning to skip_while: instead of returning true for elements that should not be yielded, it returns true for elements that should be yielded.

like image 194
trent Avatar answered Jan 11 '23 12:01

trent