作者khoguan (Khoguan Phuann)
看板C_and_CPP
标题C++ field parsing manipulator for istream
时间Mon May 23 23:58:33 2005
※ 引述《khoguan (Khoguan Phuann)》之铭言:
: ※ 引述《penggw (~梦的点滴~)》之铭言:
: : 现在我要输入一个时间
: : 格式
: : 例: 12:59
: : 9:00
: : 把小时存在int hour里面
: : 分钟存在int min里面
: : scanf("%d:%d",&hour,&min)可以输入
: : 那用cin要如何达成同样目的?
: C++ standard library 没有额外设计类似 scanf 这种
: 功能的函式可以用。或者继续沿用 scanf 或者就要写得
: 比较麻烦一点。像是
: char buf[3];
: cin.getline(buf, 3, ':'); // 到 : 为止
: int hour = atoi(buf);
: cin.getline(buf, 3); // 到 end of line 为止
: int min = atoi(buf);
以上是简单的做法。因为我感到 field parsing 是常常要用到
的操作,C++ 标准程式库未能提供现成的东西可以用,一时手痒,
就写了一个比较一般化的解法,可以指定一种或多种栏位分隔号。
因为已经超出 penggw 的需求,因此我重订了标题,尚祈海涵。
我写的工具,使用的方法,是一种 I/O manipulator 技巧的应用:
Field timef(":"); // 指定用 : 做为栏位分隔符号,可以一次指定多种符号
// 读进的资料只要遇到其中任何一个都视为栏位分隔号
// 连续两个分隔号,中间仍算是一栏,为空资料栏位
// 预设以一行为record,最後一栏後面不要再加分隔符
//Fild timef(":", false); // 这样则表示最後一栏後面要加分隔符,一栏的
// 资料就可以跨行,但是 client code 要自行
// 处理掉後面的多余字元(包括'\n'),例如使用
// cin.ignore(INT_MAX, '\n');
// 後续的输入才不会有问题
// 输入整数的例子
int hour = 0, min = 0;
cin >> timef(hour) >> timef(min); //如12:23的12存到 hour, 23存到 min
// 输入字串的例子
Field namef("|;"); // | 和 ; 都视为分隔号
string name1, name2, name3;
cin >> namef(name1) >> namef(name2) >> namef(name3);
/* 输入
Brian W. Kernighan|Dennis M. Ritchie;Bjarne Stroustrup
以後,name1 == Brian W. Kernighan
name2 == Dennis M. Ritche
name3 == Bjarne Stroustrup
*/
用 string 去接,可以输入任意长度的字串。也可以用 char arrary
去接,程式会自动将超出的输入部份丢掉,不会 overflow. 如
char n1[30], n2[30], n3[30];
cin >> namef(n1) >> namef(n2) >> namef(n3);
char array 和 char* 不同,若是用 char* 去接,只会存到whitespace
之前,并且输入栏位长度不能超过 buffer
各种 type 也可混合在一起使用。
用起来还不错 :-) 不过若要更复杂的 parsing 功能,可能就得
借用行家所做的 regular expression library 了。
程式码实作如下,敬请批评指教。
/*
* C++ Field Parsing Manipulator for istream
* by Khoguan Phuann, 2005/05/23
*/
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
using namespace std;
template <class T> struct GetField;
class Field {
public:
Field(const string& d = " ", bool e = true) : di(d), eol(e) { }
template <class T>
GetField<T> operator() (T& val) {
return GetField<T>(*this, val);
}
// 3 friend operator>>
template <class T>
friend istream& operator>> (istream& is, const GetField<T>& gf);
template <int LEN>
friend istream& operator>> (istream& is, const GetField<char[LEN]>& gf);
friend istream& operator>> (istream& is, const GetField<string>& gf);
private:
string di; // delimiters string
bool eol; // wheter \n serves as delimiter
};
template <class T>
struct GetField {
GetField(const Field& ff, T& v) : f(ff), val(v) { }
const Field& f;
T& val;
};
template <class T>
istream& operator>> (istream& is, const GetField<T>& gf)
{
string buf;
char ch;
while (is.get(ch)) {
if (gf.f.di.find(ch) != -1 || (gf.f.eol && ch == '\n')) {
istringstream istr(buf);
istr >> gf.val;
break;
}
buf += ch;
}
return is;
}
istream& operator>> (istream& is, const GetField<string>& gf)
/* overloaded for GetField<string> */
{
string tmp;
char ch;
while (is.get(ch)) {
if (gf.f.di.find(ch) != -1 || (gf.f.eol && ch == '\n'))
break;
tmp += ch;
}
gf.val = tmp;
return is;
}
template <int LEN>
istream& operator>> (istream& is, const GetField<char[LEN]>& gf)
/* overloaded for GetField<char[LEN]> */
{
string buf;
char* pc = gf.val;
char ch;
while (is.get(ch)) {
if (gf.f.di.find(ch) != -1 || (gf.f.eol && ch == '\n'))
break;
buf += ch;
}
strncpy(pc, buf.c_str(), LEN-1);
pc[LEN-1] = 0;
return is;
}
/* End of C++ Field Parsing Manipulator for istream */
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.130.208.168