【Rust】コンソールにて、スペースを挟んで2つの入力内容を各変数に格納し取り扱う方法
Rustのコンソールプロジェクトにおいて、スペースを挟んで文字列や数値等を複数入力し、それぞれ入力した内容を別個に取り扱いたい時もあります。
例として、名前と年を入力して出力する際に下記動作を求めたい場合です。
名前と年齢を、スペースを挟んでそれぞれ入力してく下さい:
magidro 28
magidroさんは28歳です。
今回はスペースを挟んで2つ以上の入力内容を取り扱うやり方を、C++での書き方と共に説明します。
【C++での書き方】
C++では文字列も数値も、 cin を用いる事で解決出来ます。
#include <iostream> using namespace std; int main(void){ string name; int age; cout << "名前と年齢を、スペースを挟んでそれぞれ入力してく下さい:\n"; cin >> name >> age; cout << name << "さんは" << age << "歳です。" << endl; return 0; }
フィルターこそ掛けていないものの、C++ では cin にて変数を並べるだけで機能します。非常に簡単ですね。出力結果は下記となります。
名前と年齢を、スペースを挟んでそれぞれ入力してく下さい:
magidro 26
magidroさんは26歳です。
もちろん、cin の後に3つ以上の変数を並べても、同様にスペースを空けて入力するだけで格納出来ます。
#include <iostream> using namespace std; int main(void){ string name; int age; int height; cout << "名前と年齢、身長をスペースを挟んでそれぞれ入力してく下さい:\n"; cin >> name >> age >> height; cout << name << "さんは" << age << "歳、身長は" << height << "cmです。" << endl; return 0; }
出力結果は下記です。
名前と年齢、身長をスペースを挟んでそれぞれ入力してく下さい:
magidro 27 172
magidroさんは27歳、身長は172cmです。
【Rustでの書き方】
ではRustで同じ処理を行なえる様に書いてみます。
use std::io; fn main() { println!("名前と年齢を、スペースを挟んでそれぞれ入力してく下さい:"); let mut word = String::new(); io::stdin().read_line(&mut word).ok(); let vec: Vec<&str> = word.split_whitespace().collect(); let name = vec[0].trim().to_string(); let age = vec[1].trim().parse().unwrap_or(0); println!("{}さんは{}歳です。", name, age); }
ポイントを説明します。
io::stdin().read_line(&mut word).ok();
これが入力を受け付ける部分です。ここでまずは word 変数にスペースを含めた文字列を格納します。参考として、「 magidro 28 」と入力します。
let vec: Vec<&str> = word.split_whitespace().collect();
一度、各入力文字列を Vector 型の vec 変数を用意し、split_whitespace() 関数を使ってスペースで区切られた文字列を vec 変数に格納します。C# での split と似た様な方法ですね。
let name = vec[0].trim().to_string(); let age = vec[1].trim().parse().unwrap_or(0);
vec 変数に格納した各文字列を、それぞれの型に変換して代入します。この場合、
・vec[0] には入力した文字列(例: magidro)
・vec[1] には入力した値(例: 28)
がそれぞれ格納されているので、それぞれ name と age に代入しております。
【3項目以上の値の取り出し方法】
この処理は、スペースで区切られた分の文字列を自動的に vec 変数に格納してくれます。 3つ文字列を入力すれば3つに、5つの文字列を入力すれば5つにそれぞれ格納する訳ですね。
let name01 = vec[0].trim().to_string(); let name02 = vec[1].trim().to_string(); let name03 = vec[2].trim().to_string(); ...
しかし、10項目以上の文字列を格納するとなると、コードが長くなりがちです。
もし変数名が全て同じでも構わないのであれば、for 文を使う手もあります。
use std::io; fn main() { println!("1 〜 100 までの得点を、スペースを挟んで1つ以上入力してく下さい:"); let mut word = String::new(); io::stdin().read_line(&mut word).ok(); let vec: Vec<&str> = word.split_whitespace().collect(); let mut score = Vec::new(); for i in 0..vec.len() { score.push(vec[i].trim().parse().unwrap_or(0)); if i == vec.len() - 1 { println!("{}点", score[i]); } else { print!("{}点 ", score[i]); } } }
任意の数の得点をスペースで区切って入力し、結果を出力するコードです。
let mut score = Vec::new();
得点の個数は任意ですので、score という名の Vector を作り、入力された分の得点を格納出来る様にします。動的にバッファを確保するという事ですね。
for i in 0..vec.len() { ... }
for 文ですが、0..vec.len() と範囲を指定する事で、vec に格納された値の個数だけ繰り返す事で、任意の得点個数に対応出来る様にします。
score.push(vec[i].trim().parse().unwrap_or(0));
実際に、score に各得点を文字列から数値に変換して代入する処理です。
・score[0] には vec[0] (1番目の得点)を代入
・score[1] には vec[1] (2番目の得点)を代入
...
という感じです。
if i == vec.len() - 1 { println!("{}点", score[i]); } else { print!("{}点 ", score[i]); }
これは結果を出力する際に、最後の得点を表示した後はスペースを入れず、改行するという処理内容を書いています。
vec.len() - 1
と「 1 」をマイナスしていますが、これは for 文の繰り返す定義が、
・0..数値の1つ前まで(例: 0..10 なら、0 〜 9まで繰り返すという意味)
である理由の為です。詳しくは公式のチュートリアルのループの項目を確認してみて下さい。
出力結果は以下となります。
【例1】
1 〜 100 までの得点を、スペースを挟んで1つ以上入力してく下さい:
1 2 3 4
1点 2点 3点 4点
【例2】
1 〜 100 までの得点を、スペースを挟んで1つ以上入力してく下さい:
85 68 27 99 100 34 7
85点 68点 27点 99点 100点 34点 7点
プログラミングのスキルチェックではこの様な処理にて解く問題もありますので、ぜひ使ってみて下さい。
以上です。