C++ field parsing manipulator for istream
※ 引述《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
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章