Rustで文字列を数値に変換(parse, from_str_radix)
Rustで文字列(String
, &str
)を数値(整数、浮動小数点数)に変換するにはparse
メソッドを使う。整数型の関連関数from_str_radix
を使うと、基数を指定して2進数や8進数、16進数表現の文字列を整数値に変換することも可能。
以下のサンプルコードでは簡単のためunwrap
を使っている。必要であればその他のメソッドやmatch
などで処理すればよい。
文字列を数値に変換: parse
文字列を数値に変換するにはparse
メソッドを使う。
数値の型T
はparse::<T>()
(ターボフィッシュ)で指定するか、変数の型注釈で指定する。
let s: &str = "100";
let i = s.parse::<i32>().unwrap();
assert_eq!(i, 100);
let i: i32 = s.parse().unwrap();
assert_eq!(i, 100);
parse
が返すのはResult
。数値に変換できない文字列の場合はエラーが返される。
let s: &str = "abc";
let is_err = s.parse::<i32>().is_err();
assert!(is_err);
parse
は型強制によってString
からも使用可能。
let s: String = String::from("100");
let i = s.parse::<i32>().unwrap();
assert_eq!(i, 100);
なお、parse
は数値に限らずFromStr
トレイトを実装する任意の型に変換できる。
let s: &str = "false";
let b = s.parse::<bool>().unwrap();
assert_eq!(b, false);
浮動小数点数に変換できる文字列表現
浮動小数点数に変換できる文字列表現はf32
およびf64
のfrom_str
のドキュメントに記載されている。f32
もf64
も同じ。
‘3.14’
‘-3.14’
‘2.5E10’, or equivalently, ‘2.5e10’
‘2.5E-10’
‘5.’
‘.5’, or, equivalently, ‘0.5’
‘inf’, ‘-inf’, ‘+infinity’, ‘NaN’
f64::from_str - Rust
e
を使った指数表記のほか、無限大inf
や非数NaN
にも変換可能。アルファベットの大文字小文字は区別されない(例えば"inf"
でも"INF"
でも"inF"
でもよい)。
assert_eq!("1.23".parse::<f64>().unwrap(), 1.23);
assert_eq!("123".parse::<f64>().unwrap(), 123.0);
assert_eq!("123.".parse::<f64>().unwrap(), 123.0);
assert_eq!(".123".parse::<f64>().unwrap(), 0.123);
assert_eq!("1.23e2".parse::<f64>().unwrap(), 123.0);
assert_eq!("1.23e-2".parse::<f64>().unwrap(), 0.0123);
assert_eq!("inf".parse::<f64>().unwrap(), f64::INFINITY);
assert_eq!("-inf".parse::<f64>().unwrap(), f64::NEG_INFINITY);
assert_eq!("infinity".parse::<f64>().unwrap(), f64::INFINITY);
assert!("nan".parse::<f64>().unwrap().is_nan());
基数を指定して2進数・8進数・16進数を変換: from_str_radix
整数型(u32
やi32
など)の関連関数from_str_radix
を使うと、基数を指定して文字列を整数に変換できる。
2進数や8進数、16進数表現の文字列を整数に変換可能。
let s: &str = "100";
assert_eq!(i32::from_str_radix(s, 2).unwrap(), 4);
assert_eq!(i32::from_str_radix(s, 8).unwrap(), 64);
assert_eq!(i32::from_str_radix(s, 16).unwrap(), 256);
基数には2以上36以下の値を指定できる。
This function panics if radix is not in the range from 2 to 36. i64::from_str_radix - Rust
第一引数の型は&str
なので、String
の場合は参照を指定する。
let s: String = String::from("ff");
assert_eq!(i32::from_str_radix(&s, 16).unwrap(), 255);
アルファベットは大文字でも小文字でもよい。
プレフィックス(0b, 0o, 0x)を判定して変換
from_str_radix
はプレフィックス(0b
, 0o
, 0x
)を考慮しない。
プレフィックス付きの文字列は3文字目以降を渡せばよい。ASCII文字のみを考慮すればいいため、スライスで部分文字列を取得できる。
- 関連記事: Rustで文字列の位置を指定して部分文字列を取得
let s: &str = "0xFF";
assert_eq!(i32::from_str_radix(&s[2..], 16).unwrap(), 255);
以下は、文字列のプレフィックスから基数を決定して整数値に変換する関数の例。なお、以降の例もそうだが、もっといい書き方があるかもしれない。
文字列の2文字目を取得し基数を決定する。エラー処理には外部クレートのanyhowを使っている。
use anyhow::{bail, ensure, Result};
fn parse_with_prefix(s: &str) -> Result<usize> {
ensure!(s.len() > 2, "too short");
let radix = match s.chars().nth(1).unwrap().to_ascii_lowercase() {
'b' => 2,
'o' => 8,
'x' => 16,
_ => bail!("unexpected radix"),
};
Ok(usize::from_str_radix(&s[2..], radix)?)
}
assert_eq!(parse_with_prefix("0b100").unwrap(), 4);
assert_eq!(parse_with_prefix("0o100").unwrap(), 64);
assert_eq!(parse_with_prefix("0x100").unwrap(), 256);
assert!(parse_with_prefix("0x").is_err());
assert!(parse_with_prefix("0a100").is_err());
assert!(parse_with_prefix("0xZZZ").is_err());
上の例では決め打ちでusize::from_str_radix
を使っている。
あまり必要ないかもしれないが、ジェネリックな関数にもできる。標準ライブラリstd
ではFromStrRadix
のようなトレイトが提供されていないため、外部クレートのnum_traitsを利用する。
use num_traits::Num;
fn parse_with_prefix_generic<T>(s: &str) -> Result<T>
where
T: Num,
<T as Num>::FromStrRadixErr: std::error::Error + Send + Sync + 'static,
{
ensure!(s.len() > 2, "too short");
let radix = match s.chars().nth(1).unwrap().to_ascii_lowercase() {
'b' => 2,
'o' => 8,
'x' => 16,
_ => bail!("unexpected radix"),
};
Ok(<T as Num>::from_str_radix(&s[2..], radix)?)
}
assert_eq!(parse_with_prefix_generic::<i16>("0xFF").unwrap(), 255_i16);
assert_eq!(parse_with_prefix_generic::<u128>("0xFF").unwrap(), 255_u128);
基数を固定してプレフィックスの有無に関わらず変換
基数を固定してプレフィックス有り無しどちらも変換したい場合もある。以下は16進数の例。
fn parse_hex(s: &str) -> Result<usize, std::num::ParseIntError> {
const RADIX: u32 = 16;
const PREFIX_L: &str = "0x";
const PREFIX_U: &str = "0X";
if s.len() < 3 {
usize::from_str_radix(s, RADIX)
} else if s.starts_with(PREFIX_L) || s.starts_with(PREFIX_U) {
usize::from_str_radix(&s[2..], RADIX)
} else {
usize::from_str_radix(s, RADIX)
}
}
assert_eq!(parse_hex("0xFF").unwrap(), 255);
assert_eq!(parse_hex("F").unwrap(), 15);
assert_eq!(parse_hex("100").unwrap(), 256);
assert!(parse_hex("0x").is_err());
assert!(parse_hex("0xZZZ").is_err());
assert!(parse_hex("xyz").is_err());
例は省略するが、2進数や8進数も同様。
なお、例えば0b100
がプレフィックスあり2進数なのか、プレフィックスなし16進数なのかを判定できないため、プレフィックスの有無か基数のどちらかは決定していなければならない。