getline() の使い方【trackのC++】

# 前文
こんにちは。
22卒でエンジニア就活をしているしがない大学生です。

エンジニア志望で就職活動をしている皆様は、
trackを使ったコーディングテストを受験することが度々あると思います。
多くのプログラミング言語に対応しており、多くの企業さんが使われていますよね。

私はC++を使って問題を解くのですが、
そこで入力のテンプレートとして使われているのが、`getline`関数。

なにこれ！入力って`cin`じゃねぇの！？
`getline`関数ってどう使うんだよ！？

ってな感じで、
問題を考える前に、入力を処理するのに解答時間の半分くらい使ってしまいました。

この記事は、
私のような人を生まないための礎となればという思いで、
書き残すものであります。

# 使い方
## サンプルコード
例えば、
入力が半角の空白で区切られているときは以下のようなコードになります。

```cpp:sumple.cpp
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <unordered_set>
#include <vector>
#include <sstream>
using namespace std;

int main() {
    string line, s;
    while (!cin.eof()) {
        getline(cin, line);
        stringstream line2(line);
        
        int i = 0;
        while( getline(line2, s, ' ') ) {
            if ( i == 0 ) {
                if ( s == "case 1" ) {
                
                } else if ( s == "case 2" ) {
               
                }
            } else if ( i == 1 ) {
            
            } else if ( i == 2 ) {

            } else {
            
            }
            ++i;
        }
    }
}
```

## 解説

```cpp:
string line, s;
while (!cin.eof()) {
    getline(cin, line); // 入力文字列を取得しlineに格納
    stringstream line2(line); // stringstream型にする
    
    int i = 0;
    while( getline(line2, s, ' ') ) { // stringstream型の入力文字列を半角空白で分割しsに格納
        if ( i == 0 ) {
            // 分割した最初の文字列に対する処理
            // sに分割した文字列が格納されているのでそれを使って処理を実装
            if ( s == "case 1" ) {
                
            } else if ( s == "case 2" ) {
               ︙
            }
        } else if ( i == 1 ) {
            // 分割した2番目の文字列に対する処理
        } else if ( i == 2 ) {
            // 分割した3番目の文字列に対する処理
               ︙
        } else {
            
        }
        ++i;
    }
```

## `getline`関数について
`getline`関数の使い方を解説します。
### 入力取得
第一引数に`cin`、
第二引数に入力文字列を格納する変数を入れることで、
入力を取得することができます。

```cpp:入力
getline(cin, line);
```
上記では`line`に入力文字列を格納しています。
### 文字列分割
第一引数に`stringstream`型の変数、
第二引数に分割した文字列を格納する変数、
第三引数に何で分割するかを入れることで、
文字列を分割してその一つ一つ取得することができます。

```cpp:空白で区切る
getline(line2, s, ' ');
```
上記では半角空白で分割した文字列を変数`s`に格納しています。

```cpp:コンマで区切る
getline(line2, s, ',');
```
上記ではコンマで分割した文字列を変数`s`に格納しています。
# 何がありがたいか
## 入力をそのまま受け取る
例えば、入力が、
「空白で区切られた任意の要素数の数字の配列が与えられる」場合。
つまり、数字は1個だけかもしれないし、2個かもしれないし、100個かもしれない。

競技プログラミングにおいては、

```
5 ←配列の要素数
1 2 3 4 5 ←配列
```
上記のような感じで配列の要素数がまず与えられ、
その後、その数だけの要素を持つ配列が与えられたりするのですが。

trackの問題においては、

```
1 2 3 4 5
```
上記のようにいきなり配列から与えられたり、

```
1 2 3 4 5
6 7
8 9 10 11 12
```
任意の要素数の配列を任意の行数入力として与えられたりします。

そんな場合でも、
**`getline`関数はとりあえず入力されたものはすべて取得します。**

問題なく、実装することが可能です。

## 妥当でない入力でも対応できる
'cin'を使った場合、決められた入力しか受け付けません。
例えば、

```cpp:input1
int a;
cin >> a;
```
上記のような使い方や、

```cpp:input_array
int a[5];
for (int i = 0; i < 5; ++i) cin >> a[i];
```
上記のような使い方が主になると思われます。

まあこれでも入力処理はできます。

が、
それは、**入力が全て妥当なものであるという保証がされている場合のみになります。**

つまり、
**想定外の入力がされた場合対応できないんですね。**

上記の`input1`は数値1つしか取得しないし、
`input_array`は5つの数値しか取得しないわけです。

いやまあ当たり前なんですが。

競技プログラミングでは、テストケースの全ての妥当性が担保されているので、
これでも問題はないです。

しかし、
実務におけるプログラミングでは、入力にバグがあることもあるのかなと思います。
例えば、
入力の途中にノイズが入ったりした場合や、
仕様で特殊な終了文字が決められている場合が考えられるでしょうか。

そういった場合でも、
**`getline`関数はとりあえず入力されたものはすべて取得します。**
比較的楽に実装することができるでしょう。

## 結論
想定外の入力に対処がしやすいのかなと思いました。
知らんけど。
# 最後に
ということで、
本記事では`getline`関数の使い方を紹介しました。

少しでも皆様のエンジニア就活の助けになったなら嬉しいです。

では。

# 参考文献
[getline - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/string/basic_string/getline.html)