在C ++中,当你在字符串流上使用带有分隔符的getline()
时,很少有我没有找到记录的东西,但是在以下情况下它们有一些非错误的方便行为:
一些测试代码(简化):
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string test(const string &s, char delim, int parseIndex ){
stringstream ss(s);
string parsedStr = "";
for( int i = 0; i < (parseIndex+1); i++ ) getline(ss, parsedStr, delim);
return parsedStr;
}
int main() {
stringstream ss("something without delimiter");
string s1;
getline(ss,s1,';');
cout << "'" << s1 << "'" << endl; //no delim
cout << endl;
string s2 = "321;;123";
cout << "'" << test(s2,';',0) << "'" << endl; //classic
cout << "'" << test(s2,';',1) << "'" << endl; //nothing before
cout << "'" << test(s2,';',2) << "'" << endl; //no delim at the end
cout << "'" << test(s2,';',3) << "'" << endl; //this shouldn't be there
cout << endl;
return 0;
}
测试代码输出:
'something without delimiter'
'321'
''
'123'
'123'
测试代码小提琴:http://ideone.com/ZAuydR
问题是 - 这可以依赖吗?如果是这样,它在哪里记录 - 是吗?
感谢您的回答并澄清:)
答案 0 :(得分:2)
标准(C ++11§21.4.8.9¶7-10)中明确记录了getline
的行为,这是关于C ++的唯一规范性文档。
您在前两个问题中询问的行为是有保证的,而第三个问题是您的测试装置如何制作的结果。
template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>& is, basic_string<charT,traits,Allocator>& str, charT delim); template<class charT, class traits, class Allocator> basic_istream<charT,traits>& getline(basic_istream<charT,traits>&& is, basic_string<charT,traits,Allocator>& str, charT delim);
效果:表现为无格式输入函数(27.7.2.3),但它不会影响值 后续调用
basic_istream<>::gcount()
返回。构造sentry
对象后, 如果sentry
转换为true
,则调用str.erase()
,然后从is
中提取字符并附加 将它们发送到str
,就像通过调用str.append(1, c)
直到发生以下任何一种情况一样:
- 文件结尾出现在输入序列上(在这种情况下,
getline
函数调用is.setstate(ios_base::eofbit)
)。- 存储
traits::eq(c, delim)
用于下一个可用的输入字符c
(在这种情况下,c
被提取但是 未附加)(27.5.5.4)str.max_size()
个字符(在这种情况下,函数调用is.setstate(ios_base::failbit
))(27.5.5.4)按照显示的顺序测试条件。在任何情况下,在提取最后一个字符后, 哨兵对象
k
被摧毁。如果函数没有提取任何字符,则会调用可能抛出的
is.setstate(ios_base::failbit)
ios_base::failure
(27.5.5.4)。返回:
is
。
回答你的问题:
找不到分隔符=&gt;然后只返回整个字符串/其余部分
这是第一个退出条件的结果 - 当输入字符串终止时,字符串流进入文件结尾,因此提取终止(在将所有前面的字符添加到输出字符串之后)。
有分隔符,但在它之前没有任何内容=&gt;返回空字符串
这只是第二点的一个特例 - 当找到分隔符时,提取终止(traits::eq(c, delim)
通常归结为c==delim
),即使之前没有提取过其他字符。
获得不存在的东西=&gt;返回可以用它读取的最后一件事
它并不完全像这样。如果流处于错误状态(sentry
对象未转换为true
,在上面的描述中) - 在您的情况下,您有一个EOF - ,getline
只留下您的字符串并返回。在您的测试代码中,您会看到最后一次读取数据,因为您正在回收相同的字符串而不在各种测试之间清除它。
答案 1 :(得分:1)
C ++工具的行为由ISO C ++标准描述。但是,它不是最可读的资源。在这种情况下,cppreference.com具有良好的覆盖率。
这是他们要说的。报价块是复制粘贴的;我对你的问题进行了穿插解释。
表现为
UnformattedInputFunction
,但input.gcount()
不受影响。构造并检查岗哨对象后,执行以下操作:
“构造和检查哨兵”意味着如果在流上检测到错误条件,则该函数将返回而不执行任何操作。这就是为什么在#3中,当“什么都不存在”时,你会观察到最后一个有效的输入。
1)调用str.erase()
因此,如果在分隔符之前没有找到任何内容,则会得到一个空字符串。
2)从输入中提取字符并将它们附加到str,直到出现以下情况之一(按所列顺序检查)
a)输入的文件结束条件,在这种情况下,getline设置
eofbit
。
这是一个错误条件,导致后续string
getline
局部变量不变。
它还允许您在结束之前观察输入的最后一段,因此如果您愿意,可以将文件结束视为分隔符。
b)下一个可用的输入字符是delim,由
Traits::eq(c, delim)
测试,在这种情况下,分隔符字符是从输入中提取的,但不会附加到str。c)存储了str.max_size()字符,在这种情况下,getline设置failbit并返回。
3)如果由于某种原因没有提取任何字符(甚至没有丢弃的分隔符),则getline设置
failbit
并返回。