CSV(逗号分隔)、文本文件(制表符分隔) 等文件的读取

来源:互联网 发布:淘宝管控下架什么意思 编辑:程序博客网 时间:2024/05/17 21:56
#include <cstring>
#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;
}

原创粉丝点击