Char : how to get next char in rust

if i want to get the next character from alphabets how to do it. let's suppose i have string "hello" and i want to move each character by 4 position "lipps". how to do it

Here's a sketch of a possible approach:

fn add1_char(c: char) -> char {
    std::char::from_u32(c as u32 + 1).unwrap_or(c)
}

fn add1_str(s: &str) -> String {
    s.chars().map(add1_char).collect()
}
4 Likes

If I understand @Harry's intent correctly, he will probably also want to add some range checks (is this an alphabetic character ?) and some modulo-based wraparound (to handle the end of the alphabet) to this sketch.

1 Like

Just to have mentioned it: depending on what it is that you want you might be better off using the unicode_segmentation crate, which provides an iterator that yields graphemes rather than chars.
This distinction doesn't matter when you just want bytes or chars, but is very important when working with non-ascii (i.e. Unicode) texts (e.g. in UTF-8).

2 Likes

Here is simple example satisfying your requirements:

fn move_shift(data: &String, shift: usize) -> String {
    data.chars().map(|c| (c as u8 + shift as u8) as char).collect::<String>()
}
1 Like

yes.

If your alphabet is small Latin letters from a to z, then this code will work:

#[derive(Debug)]
struct MyError;

fn shift(input: &str, shift: i8) -> Result<String, MyError> {
    let mut buf = Vec::with_capacity(input.len());
    for byte in input.bytes() {
        match byte {
            b'a'..=b'z' => {
                let mut val = byte as i16 + shift as i16;
                if val > b'z' as i16 || val < b'a' as i16 {
                    val -= b'a' as i16;
                    val = if val >= 0 {
                        (val % (b'z' as i16)) + b'a' as i16
                    } else {
                        1 + b'z' as i16 + (val % (b'z' as i16))
                    }
                }
                buf.push(val as u8);
            }
            _ => Err(MyError)?,
        }
    }
    let out = String::from_utf8(buf)
        .expect("we are sure that all bytes fall into ASCII range");
    Ok(out)
}

fn main() {
    println!("{:?}", shift("hello", 4).unwrap());
    println!("{:?}", shift("abcdef", -3).unwrap());
}

It prints "lipps" and "xyzabc". It can be done without allocating additionall string, though code will be a bit more complex.