Syntactic Fructose
Syntactic Fructose

Reputation: 20144

Invert string in Rust

I'm trying to do a simple string inversion in Rust, but I can't seem to figure out what functions to use in order to do this.

Say I have a string: ____x_xx__x

inverting this string will become: xxxx_x__xx_

I tried:

//res is the string I want to invert
for mut c in res.as_slice().chars() {
  c =
    match c {
      'x' => '_',
       _  => 'x'
    };
};

but this warns me that the value c is never read, so I guess the c I am using is not actually a reference to the character in the slice?

Upvotes: 2

Views: 635

Answers (3)

user439299
user439299

Reputation: 841

Here is my take:

http://is.gd/uXdoRf

fn new_str(s: &String) -> String {
    let mut s2 = String::new();
    for i in range(0,s.len()) {
        s2 = s2.append(if s.as_slice().char_at(i) == '_' { "x" } else { "_" });
    }
    s2
}

fn in_place(s: &mut String) {
    for _i in range(0,s.len()) {
        let c = s.shift_char();
        match c {
            Some(x) => s.grow(1,if x == '_' { 'x' } else { '_' }),
            None => return
        }
    }
}

fn main() {
    let s = String::from_str("___xxx__x_");
    let s2 = new_str(&s);
    println!("{}",s);
    println!("{}",s2);
    let mut s3 = String::from_str("___xxx__x_");
    in_place(&mut s3);
    println!("{}",s3);
}

Output:

___xxx__x_
xxx___xx_x
xxx___xx_x

Annoyingly enough the in place version is O(n^2) since "shift_char" is O(n). I'm not sure how to alter a single character directly though.

Upvotes: 1

oblitum
oblitum

Reputation: 12016

fn main() {
    let mut res = String::from_str("____x_xx__x").into_ascii();

    for c in res.mut_iter() {
        *c = match c.to_char() {
            'x' => '_',
             _  => 'x'
        }.to_ascii();
    };

    println!("{}", res.into_string());
}

play.rust-lang.org

Upvotes: 3

Chris Morgan
Chris Morgan

Reputation: 90912

.chars() yields char instances which are not references in any way.

To be able to modify such a thing in place, you would need to have a mutable slice.

A String is UTF-8 encoded; if you wish to do it in place, any character replacement must be for a character with the same number of bytes; the simplest case for that is ASCII. (And with your examples of x and _, it must be ASCII.)

The way to implement this in place would be as_mut_bytes() and its mut_iter():

let bytes = unsafe { res.as_mut_slice() };
for c in bytes.mut_iter() {
    *c = match *c {
        'x' => '_',
        _ if c.len_utf8_bytes() > 1 => fail!("you tried to make me make bad UTF-8"),
        _ => 'x',
    }
}

(I inserted the len_utf8_bytes() branch to guarantee the UTF-8 invariant. It may be omitted—though putting it as a debug_assert! is still probably a good idea—if you know you’re only dealing with ASCII.)


Alternatively, you could create a new string out of it. This would cope with non-ASCII strings.

res.chars().map(|c| if c == 'x' { '_' } else { 'x' }).collect::<String>()

Using codepoints as the boundaries isn’t very precise either, so let’s work with grapheme clusters for this case instead.

res.graphemes(true).map(|c| if c == "x" { '_' } else { 'x' }).collect::<String>()

Upvotes: 3

Related Questions