C++读取文本文件中含空格的第二个字符串问题
嘿,这个问题我之前处理类似的日志文件时也踩过坑!核心问题就在于第二个字段是可能包含空格的字符串——用cin >>的话会在第一个空格就停住,直接用getline又会把整行都读进来,完全没法区分字段。结合你给出的行格式(int - 带空格字符串 - int - float - float - 无空格字符串 - 带空格时间串),给你几个实用的解决方案:
方案1:利用字段类型特征分割(最稳妥)
因为第三个字段是整数,我们可以在读出第一个整数后,逐个字符读取直到遇到数字(整数的开头),这之间的内容就是带空格的第二个字段。剩下的字段里,除了最后一个时间串,都是无空格的,可以直接用>>读取,最后用getline获取剩余的时间内容。
示例代码(C++):
#include <iostream> #include <string> #include <sstream> #include <cctype> using namespace std; int main() { int id, duration; float heartRate, calories; string intensity, timestamp, choiceName; string line; // 读取整行内容 while (getline(cin, line)) { istringstream iss(line); // 读取第一个整数ID iss >> id; // 提取带空格的choiceName:直到遇到数字(第三个字段的开头) char c; while (iss.get(c)) { if (isdigit(c)) { iss.unget(); // 把数字放回输入流,留给后面读取duration break; } choiceName += c; } // 清理choiceName前后的多余空格 size_t start = choiceName.find_first_not_of(" "); size_t end = choiceName.find_last_not_of(" "); if (start != string::npos && end != string::npos) { choiceName = choiceName.substr(start, end - start + 1); } else { choiceName.clear(); } // 读取后续无空格的字段 iss >> duration >> heartRate >> calories >> intensity; // 读取剩余的时间串(包含空格) getline(iss, timestamp); start = timestamp.find_first_not_of(" "); if (start != string::npos) { timestamp = timestamp.substr(start); } // 输出测试 cout << "ID: " << id << endl; cout << "Choice Name: '" << choiceName << "'" << endl; cout << "Duration: " << duration << endl; cout << "Heart Rate: " << heartRate << endl; cout << "Calories: " << calories << endl; cout << "Intensity: '" << intensity << "'" << endl; cout << "Timestamp: '" << timestamp << "'" << endl; cout << "-------------------------" << endl; // 重置字符串,避免下一行读取时残留内容 choiceName.clear(); timestamp.clear(); } return 0; }
代码说明:
- 先读取整行到
stringstream,方便灵活操作; - 读出第一个整数后,逐个字符读取,直到碰到数字(第三个字段的开头),把这个数字放回流中,之前的字符就是带空格的第二个字段;
- 清理字段前后的多余空格,保证内容整洁;
- 后面的
duration、heartRate、calories、intensity都是无空格的,直接用>>读取; - 最后用
getline读取剩余的所有内容,就是带空格的时间戳。
方案2:拆分所有单词后反向提取(适合确定后续字段数量的场景)
如果能确定:除了第二个和最后一个字段,其他都是单个单词(无空格),可以先把整行拆成单词数组,然后通过索引提取固定位置的字段,中间的单词拼接成第二个字段,最后几个单词拼接成时间戳。
示例代码:
#include <iostream> #include <string> #include <sstream> #include <vector> using namespace std; int main() { string line; while (getline(cin, line)) { istringstream iss(line); vector<string> tokens; string token; // 把整行拆成单个单词的数组 while (iss >> token) { tokens.push_back(token); } // 提取固定位置的字段 int id = stoi(tokens[0]); int duration = stoi(tokens[tokens.size() - 5]); float heartRate = stof(tokens[tokens.size() - 4]); float calories = stof(tokens[tokens.size() - 3]); string intensity = tokens[tokens.size() - 2]; // 拼接带空格的choiceName(从第1个到倒数第6个单词) string choiceName; for (int i = 1; i < tokens.size() - 5; ++i) { choiceName += tokens[i] + " "; } if (!choiceName.empty()) { choiceName.pop_back(); // 去掉最后多余的空格 } // 拼接带空格的时间戳(从倒数第4个到最后一个单词) string timestamp; for (int i = tokens.size() - 4; i < tokens.size(); ++i) { timestamp += tokens[i] + " "; } if (!timestamp.empty()) { timestamp.pop_back(); } // 输出测试 cout << "ID: " << id << endl; cout << "Choice Name: '" << choiceName << "'" << endl; cout << "Duration: " << duration << endl; cout << "Heart Rate: " << heartRate << endl; cout << "Calories: " << calories << endl; cout << "Intensity: '" << intensity << "'" << endl; cout << "Timestamp: '" << timestamp << "'" << endl; cout << "-------------------------" << endl; } return 0; }
注意点:
这个方案依赖于你对字段数量的精准判断——比如你的示例中时间戳是4个单词,所以从倒数第4个到最后一个拼接。如果时间戳的单词数量可能变化,这个方案就不太适用了,还是方案1更稳妥。
总结
两种方案的核心思路都是利用已知的字段格式特征,区分带空格和无空格的字段。如果字段格式可能有变化(比如时间戳的单词数不固定),优先选方案1;如果格式完全固定,方案2的代码会更简洁。
内容的提问来源于stack exchange,提问作者Cartino
相关产品推荐
相关产品推荐

