본문 바로가기

Rust/pure

[rust] 숫자 parse 할 때 주의점

백준 문제를 rust 언어로 풀어보려고 하다가, 문자열을 파싱하는 과정에서 계속 오류가 발생했다.

    let mut buf = String::new();
    stdin().read_line(&mut buf).expect("cannot read line!");
    let N = buf.parse::<usize>().unwrap();

코드만 보면 별 문제가 없어 보이지만, 위 코드를 통해 숫자를 입력하는 경우 panic이 발생한다.

panic이 발생한 모습

https://doc.rust-lang.org/std/io/trait.BufRead.html#method.read_line

 공식 문서에 따르면 Stdin::read_line은 개행 문자('\n' == 0xA == 라인 피드)를 만날 때까지 문자열을 읽어 들인다. 다만 라인을 읽어들일 때 개행 문자까지 버퍼에 포함된다. 간단한 코드로 이를 증명해보자.

let mut buf = String::new(); // 이거 안됨
stdin().read_line(&mut buf).expect("cannot read line!");
println!("{}", buf);

출력된 결과

 출력된 모습을 보면 개행이 2번 일어난 것을 볼 수 있다. prinln! 매크로에 의해 1번, 문자열에 포함된 것 1번으로 총 2번의 개행이 발생한 것이다. 따라서 위 방식으로 숫자를 입력받는 경우 버퍼에 숫자와 개행문자가 포함된다.

 rust의 parse 함수는 다른 편리한 언어들과는 달리 공백이나 개행문자를 자동으로 제거하지 않는다. 이런 에러가 특히 익숙하지 않았던 이유는 자주 사용하는 자바스크립트 언어의 경우 공백 문자를 숫자로 파싱하는 과정에서 알아서 처리해줬기 때문이다. 평소에 별로 생각할 부분이 아니라 떠올리지 못한 것 같다.

자바스크립트는 신이야

 아무튼 위와 같은 이유로 rust에서 parse을 통해 정상적인 형 변환이 가능하려면 입력받은 버퍼로부터 공백 문자들을 제거해야 한다. 이는 trim을 통해 수행할 수 있다. 만약 문자열 시작 또는 끝만 없애고 싶다면 start_trim / end_trim을 고려하자.

let mystr = String::from("\n\n\nhello, world!\n\n\n");
println!("mystr: {}", mystr);
println!("mystr: {}", mystr.trim());

trim에 의해 앞 뒤 문자열이 제거된 모습. ( &str, 슬라이싱 기반)

이 정보들을 조합하면, 다음 코드를 통해 문제 없이 문자열을 숫자로 파싱할 수 있다.

let mut buf = String::new();
stdin().read_line(&mut buf).expect("cannot read line!");
let N = buf.parse::<usize>().unwrap();
println!("{}",N);

출력된 모습

'Rust > pure' 카테고리의 다른 글

[rust] 문자열 문자 단위로 나누기  (0) 2023.03.26
[Rust] 함수(function)  (0) 2021.11.08
[Rust] 변수  (0) 2021.10.28