How to parse an int from string?


#1
let string = "Rust4Fun";
assert_eq!(4, string.parse_int());

I want to get the int from the string as above, so could you give me some tips to implement the parse_int() method?


#2
fn parse_int(_: &str) -> i32 { 4 }

Or can you specify your input more concrete?

Is "a3" expected to be 3? Whats about "a1b2c"? etc…


#3

sorry for inaccurate description.
input_string contains just ONE integer character and just parse out that integer.

fn parse_int(strr: &str) -> i32 {
    unimplement()!;
}

#4

You can use;
String chars() function
char is_digit() and to_digit() functions
https://doc.rust-lang.org/std/

For more elaborate extractions regex is a popular choice.
https://crates.io/crates/regex


#5
  • iterate over chars
  • skip non-digits
  • take first element
  • convert to i32
  • sub '0' as i32 from that value
  • be happy

This really reads like an exercise/homework. It is a very basic operation and most languages I am aware of use similar steps to solve this exercise


#6

There’s a few char functions that are good if you are parsing single digits, especially to_digit.


#7

@jonh I have never thought of using regex, thanks, I’ll try it.
@NobbZ
@bluss thank you. I have done it with iteration and digit convertion.
yes, this is a small problem in an OJ, sorting some strings with the number it contains.


#8

Something like this could work:

fn parse_int(input: &str) -> Option<u32> {
    input.chars()
        .find(|a| a.is_digit(10))
        .and_then(|a| a.to_digit(10))
}

The 10 just means that it’s a base 10 digit, as opposed to a hexadecimal digit (where a-f could be considered a digit).


#9

I understand your goal, but an arbitrary string may not be parseable into an integer. So, in general, you would need some way to indicate whether the parsing happened successfully. The idiomatic way to do that in Rust is with the Result or Option types.

Others have given good answers already, but just want to mention there is already a pre-defined method in std for this conversion:
https://doc.rust-lang.org/std/primitive.i32.html#method.from_str_radix

Edit: This method does not skip leading or trailing non-digits. It would also convert as many consecutive integers it can find, but we can handle that by taking a slice of 1 char.

let res = string.chars().skip_while(|c| !c.is_digit(10)).collect::<String>();
let i = i32::from_str_radix(&res[0..1], 10);
match i { ... }

Link to playground
This approach would make it easier to generalize to more than one char or non-decimal bases. Just my 2 cents.


#10

input_string contains just ONE integer character

If the expected input is one character, isn’t it better to define the function as taking a character or a byte (u8)?


#11

Nope, since as the example suggests, we have a single digit wrapped into an arbitrary number of preceeding and suceeding letters (or maybe other chars).


#12

If you decide you need to support more than one char ints you can use something along these lines:

fn parse_int(input: &str) -> Option<u32> {
    input
        .chars()
        .skip_while(|ch| !ch.is_digit(10))
        .take_while(|ch| ch.is_digit(10))
        .fold(None, |acc, ch| {
            ch.to_digit(10).map(|b| acc.unwrap_or(0) * 10 + b)
        })
}

or https://doc.rust-lang.org/std/primitive.str.html#method.parse with some slicing