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.9 的 to_string/stoi 就夠了,知道有這條路即可。
¶重複使用同一條 stringstream?先重置
本節的範例每讀一行就開一條新的 stringstream,用完即丟——這是最不容易出錯的寫法,優先照做。若真的要重複使用同一條,有個地雷: