How to reverse output all characters of a String type?

Hullo, folks. I want to output the reverse of a String value.
Like, the reverse of "Hello, world!” is “!dlrow,olleH” is what I want.
Here is the code:

fn main() {
    let s1 = String::from("Hello, world!");
    let (s1, s2) = reverse_string(s1);
    println!("The reverse of \"{}\" is \"{}\".", s1, s2);
}
fn reverse_string(s: String) -> (String, String) {
    let length = s.len();
    let reversed_s: String;
    for number in (0..length).rev() {
        reversed_s.push_str(s[number]);
    }
    (s, reversed_s)
}

Compile error:

  "String` cannot be indexed by `usize`"  

The problem appears to lie in

reversed_s.push_str(s[number]);

How can I get each character of a String type ?
How to reverse output all characters of a String type?
Any concise and easy way?

You can get 1 character string[i..i+1], strings can’t be indexed because multiple bytes may make up a single visual character and Rust doesn’t want to make that decision. Another way is string.chars().nth(i)

Easiest is just to do rev() on the characters:
let reversed = s.chars().rev().collect()

3 Likes

If your string may contain multi-character grapheme clusters, then simply printing the chars in reverse may produce unexpected results.

For example, the string "man\u{0303}ana" displays as "mañana" forward, but s.chars().rev().collect() displays as "anãnam". (The tilde is now above the wrong letter.)

You can use the unicode-segmentation crate to iterate over graphemes instead of chars:

use unicode_segmentation::UnicodeSegmentation;

fn main() {
    let x = "man\u{0303}ana";
    let y: String = x.graphemes(true).rev().collect();
    println!("{}", y); // prints "anañam"
}
13 Likes

Tip: reverse_string() can takes a &str and returns a String.

fn main() {
  let s1 = String::from("Hello, world!");
  let s2 = reverse_string(&s1);
  println!("The reverse of \"{}\" is \"{}\".", s1, s2);
}

fn reverse_string(s: &str) -> String {
  s.chars().rev().collect()
}
1 Like

Slightly offtopically, this is what I see in my Firefox, even though copying the word elsewhere indeed shows the tilde over ‘a’.


Unicode is hard.

Reversing a Unicode string “correctly” is my favorite impossible task. Ligatures like “ffi”. Korean, where it seems like it’d make sense to reverse “letters” composing the blocks, but this wouldn’t make sense to Korean speakers. Arbitrary sequences that make non-standard emoji with zero-width joiners. Flag emoji. And the wild ride of bi-directional text that’s tricky to manage even in its normal direction(s).

3 Likes

Ligatures are only used when displaying a text in a particular font. They usually aren’t part of the string.

Coincidentally, this is the 2nd exercise on the Rust track of exercism.io.

Is this task actually useful? I thought reversing a string is just a nice exercise, but never happens in actual code.

See also: https://docs.rs/unicode-reverse/1.0.8/unicode_reverse/

And https://docs.rs/bstr/0.1.4/bstr/struct.BStr.html#method.reverse_graphemes, if you don’t have a UTF-8 invariant.

1 Like

ffi ligature is U+FB03, so it may be a part of the string. I run into it when copying stuff from PDFs.

 effing unicode
4 Likes