C++ 使用C++;溪流
使用C++ 使用C++;溪流,c++,iostream,C++,Iostream,使用stdio.h时,我可以很容易地读取某些类型的格式化输入,如下所示: FILE* fin = fopen(...); fscanf(fin, "x = %d, y = %d", &x, &y); int x, y; string s; getline(cin, s, '='); cin.get(); // Get rid of = cin >> x; getline(cin, s, '='); cin >> y; 最棒的是,我真的不必担心字符“x
stdio.h
时,我可以很容易地读取某些类型的格式化输入,如下所示:
FILE* fin = fopen(...);
fscanf(fin, "x = %d, y = %d", &x, &y);
int x, y;
string s;
getline(cin, s, '=');
cin.get(); // Get rid of =
cin >> x;
getline(cin, s, '=');
cin >> y;
最棒的是,我真的不必担心字符“x”和下面的“=”之间有多少空格,以及其他小细节
在C++中,我觉得好像,
ifstream fin(...);
string s;
fin >> s;
可能导致s
为“x”
或“x=”
,甚至“x=12”
,具体取决于输入的间距
使用iostream
/fstream
是否有一种方便的方法来获得类似于scanf
/fstream
的行为?简短的回答是“否”
一个稍微长一点的回答是“你可能可以构建这样的东西”。例如,您可以读取文本行,然后使用合适的“用空字符串替换空格”类型函数。或者像这样:
FILE* fin = fopen(...);
fscanf(fin, "x = %d, y = %d", &x, &y);
int x, y;
string s;
getline(cin, s, '=');
cin.get(); // Get rid of =
cin >> x;
getline(cin, s, '=');
cin >> y;
或者,使用cin.ignore
跳过某些内容(因为字符串读取不是很有用,除非您想知道“x”和“y”实际上是“x”和“y”):
int x, y;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> x;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> y;
如果有人输入了超过100k个字符,但没有=符号,则此操作将“中断”,并且需要进行错误检查,以确保“垃圾”不会出现-就像fscanf
所做的那样。if(cin>>x)
将处理此问题“发现出了问题,但你需要做一些明智的事情,因为它出了问题,我现在不确定
当然,由于C++支持(几乎)所有的C,所以当然,你也可以使用你希望使用的
非常全面。流操纵器位于页面底部附近。考虑到一个先决条件,这实际上非常简单。我有这三个函数,我将它们粘贴在某个标题中。它们允许您以字符文本和字符串文本进行流式处理。我一直不太明白为什么这些不是标准的
#include <iostream>
//These are handy bits that go in a header somewhere
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e(&sliteral)[N]) {
e buffer[N-1] = {}; //get buffer
in >> buffer[0]; //skips whitespace
if (N>2)
in.read(buffer+1, N-2); //read the rest
if (strncmp(buffer, sliteral, N-1)) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
e buffer(0); //get buffer
in >> buffer; //read data
if (buffer != cliteral) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
//redirect mutable char arrays to their normal function
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, e(&carray)[N]) {
return std::operator>>(in, carray);
}
对于更复杂的情况,您可能需要使用
std::regex
或boost::regex
,或者可能需要一个真正的lexer/解析器。有趣!我也想知道:)您可以使用具有忽略空白作为分隔符的方面的区域设置。@0x499602D2:正常区域设置将空白作为分隔符。一个不将空白作为分隔符的区域设置在这里似乎没有帮助(至少对我来说)。(显然)需要的是,字母、逗号和等号被视为空白(除了正常的空白字符之外)。@JerryCoffin我相信你能做到。你为什么不把它作为一个答案呢?:)您没有补偿,
,这是必需的,因为iStream是以空格分隔的。@Adrian他的代码完全忽略逗号,直接读取两个数字。逗号可能在那里,也可能不存在,这两种方式的效果都是一样的。@MooingDuck True,但这可能会被解析为错误,具体取决于需求。我发现采用字符串文字的函数不处理像fscanf()
这样的嵌入空格,但这仍然很好。但是,最后一个函数的目的是什么?如果要调用第一个函数,我看不出它会如何正常工作。看起来它会递归地调用自己,直到堆栈崩溃。@Adrian:看起来是这样,但实际上不是这样。第一个捕获常量(&)[N]。第二个捕获常量&<代码>标准::基本流::运算符>>捕获e&
。不幸的是,第一个也将捕获e(&)[N]
(noncst),因此我有一个覆盖,它显式地将它转发给std::operator>(…,e(&)[N])
。(请注意,std::operator>
位于std
命名空间中,它们位于全局命名空间中,因此没有递归)@Adrian:是的,字符串文本用于类似于>>中的的“name”>'='>>值代码>。我认为允许/不允许像scanf这样的空间可能是有道理的。我和我的朋友就字符串文字的输入是否应该忽略前面的空白以及它应该如何处理内部空白争论了一段时间。像fscanf
那样做是有道理的,我可能会修改它来做到这一点。这会大大增加复杂性,但会很方便。根据您的需要,使用regex
可能会有点臃肿。@MooingDuck,您好,请为我指出正确的方向,以便了解您在这里做了什么?我对C++和OOP有基本的了解,但对流和模板的了解很少,我想了解更多。最让我困惑的是const(&sliteral)[N]
以及它是如何工作的,从我的理解来看,它实例化了一个以字符串文本的地址作为参数构造的对象数组,但与此同时,我不知道在重载运算符的签名中如何实现这一点。一句话:我很困惑。