語法書 / AA 競程語法書 下冊 / 第十單元 / getline 與 stringstream:整行讀入

10.10 getline 與 stringstream:整行讀入

cin >> s 讀到空白就停,但有些題目一行就是一筆資料(句子含空白)。8.7 的補充教過 C 字串版的 cin.getline(s, 105),得帶大小上限;string 版是一個獨立函式 getline(cin, s):讀到換行為止、換行本身被讀走丟棄、長度不設限:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string line;
    getline(cin, line);                // 讀一整行(結尾換行被讀走丟棄)
    cout << line.size() << '\n';       // 空白也算在長度裡
    cout << line << '\n';
    return 0;
}

執行結果(輸入 I love AACPSCHOOL):

17
I love AACPSCHOOL

先猜再跑:輸入第一行是 3 後面跟著三個空白、第二行是 abc def。跑 cin >> n; cin.ignore(); getline(cin, line); 之後,line 的內容是什麼?(提示:cin.ignore() 只丟掉一個字元。)

stringstream:把一行再拆開

整行拿到手了,新問題跟著來:這一行裡有數量不定的數字,怎麼一個個拆出來?答案是 <sstream> 標頭檔的 stringstream:把一個字串變成一條「迷你輸入流」,之後用起來跟 cin 一模一樣:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    string line;
    while (getline(cin, line)) {       // 一次讀一整行,EOF 時結束
        stringstream ss(line);         // 把這一行變成一條「迷你輸入流」
        int x, sum = 0;
        while (ss >> x) {              // 用法跟 cin >> 一模一樣,只是來源是這一行
            sum += x;
        }
        cout << sum << '\n';
    }
    return 0;
}

拿這份程式跑跑看下面的測試資料(每行的數字數量都不同):

1 2 3
10 20
7

執行結果:

6
30
7

外層 while (getline(...)) 逐行掃,內層 while (ss >> x) 把該行的數字一個個撈出來、撈完自動停(撈到不能解析成數字的內容也會停,不會跳過它繼續找)——「每行數量不定」這種用上冊工具處理起來非常麻煩的輸入格式,兩層迴圈優雅收工。

拆出來的也可以是字串

ss >> 右邊放什麼型態,就拆出什麼:換成 string,拆出來的就是一個一個單詞。和 cin >> 一樣,它會跳過連續的空白,行尾多餘的空白也不會多拆出東西:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    stringstream ss("red  green   blue  ");
    string word;
    while (ss >> word) {
        cout << word << '\n';
    }
    return 0;
}

執行結果:

red
green
blue

自訂分隔字元:getline 的第三個參數

不是所有輸入都用空白隔開——日期用 -、清單用逗號。getline 還有一個三參數版本getline(ss, part, '-'),意思從「讀到換行為止」改成「讀到指定的分隔字元為止」(對 cin 也可以這樣用):

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    stringstream ss("2026-08-01");
    string part;
    while (getline(ss, part, '-')) {
        cout << part << '\n';
    }
    return 0;
}

執行結果:

2026
08
01

stringstream 也能「寫」

到目前為止 stringstream 都在「讀」;它其實同時支援讀和寫——ss << 東西 把內容累積進去,ss.str() 把目前累積的整串內容取出來變成 string:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    stringstream ss;
    int y = 2026, m = 8;
    ss << y << '/' << m;               // 數字和符號拼在一起
    string s = ss.str();               // 取出目前累積的內容
    cout << s << '\n';
    return 0;
}

執行結果:

2026/8

「寫進去、讀出來」也能完成數字與字串的互相轉換(ss << 999;ss >> s;)——不過 Level 0 用 10.9to_stringstoi 就夠了,知道有這條路即可。

重複使用同一條 stringstream?先重置

本節的範例每讀一行就開一條新的 stringstream,用完即丟——這是最不容易出錯的寫法,優先照做。若真的要重複使用同一條,有個地雷: