CSV(逗號分隔)、文本文件(製表符分隔) 等文件的讀取

#include
#include <string>
#include <fstream>

template<class callbackfun> bool csvread( const char* filename, callbackfun cbf, char delimit=',' )
{
    std::ifstream file( filename, std::ios::binary );
    if( !file ) return false; // 文件打開失敗

    bool quo = false; // 此字段是否以雙引號開始
    bool quopre = false; // 當此字段以雙引號開始時,前一個是否爲雙引號
    std::string val;
    size_t row=0, col=0;

    for( char c; file.get(c); )
    {
        if( c == delimit )
        {
            if( quo && !quopre )
            {
                val += c;
            }
            else
            {
                if( !cbf(row,col,val) )
                    return false;
                quo = false;
                quopre = false;
                val.clear();
                ++col;
            }
        }
        else switch( c )
        {
        case '"':
            if( !quo )
            {
                if( val.empty() )
                    quo = true;
                else
                    val += c;
            }
            else if( quopre )
            {
                quopre = false;
                val += c;
            }
            else
                quopre = true;
            break;
        case '\r':
            break;
        case '\n':
            if( quo )
            {
                val += c;
            }
            else
            {
                if( !cbf(row,col,val) )
                    return false;
                quo = false;
                quopre = false;
                val.clear();
                ++row;
                col = 0;
            }
            break;
        default:
            if( quopre )
            {
                quo = false;
                quopre = false;
            }
            val += c;
            break;
        }
    }

    if( !val.empty() || col!=0 )
    {
        if( !cbf(row,col,val) )
            return false;
    }

    return file.eof();
}

void csvvalue( const char* str, std::string& val )
{
    if( str[strcspn(str,",\"\n")] == '\0' )
    {
        val.clear();
        return;
    }

    // 如果有 逗號 分號 換行,則用引號括起來,並把其中原有的引號變爲雙份
    val = '"';
    const char* p1 = str;
    for( const char* p2; (p2=strchr(p1,'"'))!=0; p1=p2+1 )
    {
        val.append( p1, p2-p1+1 );
        val.append( 1, '"' );
    }
    val.append( p1 );
    val.append( 1, '"' );

    return;
}

//////////////////// 以下爲測試 ////////////////////

#include <iostream>
#include <locale>
using namespace std;

struct foo
{
    foo() : row(0), col(0)
    {
    }

    size_t row, col;

    bool operator()( size_t r, size_t c, std::string val )
    {
        if( r != row )
            cout << '\n';
        if( c != 0 )
            cout << '|';
        cout << val;
        row=r, col=c;

        return true;
    }
};

int main()
{
    // 否則打開含中文的路徑失敗,但可惜的是MinGW用之無效,又不支持"chs"
    std::locale loc = std::locale::global( std::locale(std::locale(),"",std::locale::ctype) );
   
    csvread( "C:\\Documents and Settings\\0846\\桌面\\Book1.csv", foo() );

    std::string val;
    csvvalue( "\"a\"\"b\"\"", val );

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章