Cocos2dx杂记:cocos2dx解析csv格式文件

游戏存储或者配置经常使用到逗号分隔文件,如何实现解析呢?

下面直接上代码

1、头文件CSVParser.h

#pragma once
#include "cocos2d.h"
#include <vector>
#include <string>
using namespace  std;

USING_NS_CC;

namespace CSVParser {

    // 每一行的记录
    class Row
    {
    public:
        Row() { }
        ~Row() { }

        void push_back(const string& value) { m_values.push_back(value); }
        void setHeader(const vector<string>* header) { m_header = header; }

    public:

        // 每行数据有多少字段
        unsigned int size() const { return m_values.size(); }

        // 运算符 [] 重载
        string& operator[](unsigned int key)
        {
            if (key < size()) return m_values[key];
            throw "can't return this value (doesn't exist)";
        }

        // 运算符 [] 重载
        string& operator[](const string& key)
        {
            vector<string>::const_iterator it;
            int pos = 0;
            for (it = (*m_header).begin(); it != (*m_header).end(); it++) {
                if (key == *it) return m_values[pos];
                pos++;
            }
            throw "can't return this value (doesn't exist)";
        }

    private:
        const vector<string>* m_header;
        vector<string> m_values;
    };


    class Csv
    { 
    public:
        Csv(const string& filename);
        ~Csv();

        // 解析csv文件
        void Parse(const string& filename);

        // 错误信息
        const string& getErrorInfo() const { return m_strErrorInfo; }

        // 获取列头字段
        vector<string> getHeader() const { return m_header; }
        // 获取总行数
        unsigned int getRowCount() const { return m_content.size(); }
        // 获取总列数
        unsigned int getColumnCount() const { return m_header.size(); }
        // 运算符 [] 重载
        Row& operator[](unsigned int key);

    private:
        // 读取整个文件的数据
        void Load(const string& filename, string& Data);
        void setHeader();

    private :
        // 原始表格数据
        vector<Row> m_content;   // 所有行的数据(包含列头)
        vector<string> m_header; // 列头字段
        // 错误信息
        string m_strErrorInfo;
    };
}

2、实现CSVParser.cpp

#include "CSVParser.h"

namespace CSVParser {

    Csv::Csv(const string& filename) {
        Parse(filename);
    }

    Csv::~Csv() {

    }

    void Csv::Load(const string& filename, string& Data)
    {
        ssize_t len = 0;
        unsigned char *data = NULL;
        auto strPath = FileUtils::getInstance()->fullPathForFilename(filename);

        data = FileUtils::getInstance()->getFileData(strPath.c_str(),"r", &len);

        Data.assign((char *)data, len);

        free(data);
    }


    void Csv::Parse(const string& filename)
    {
        // 清除之前的数据
        m_content.clear();
        m_strErrorInfo.clear();

        string text;
        Load(filename, text);

        if (text.size() == 0) {
            return;
        }

        // 定义状态
        enum StateType {
            NewFieldStart,      // 新字段开始
            NonQuotesField,     // 非引号字段
            QuotesField,        // 引号字段
            FieldSeparator,     // 字段分隔
            QuoteInQuotesField, // 引号字段中的引号
            RowSeparator,       // 行分隔符字符1,回车
            Error,              // 语法错误
        };

        Row Fields = Row();
        string strField;

        // 设置初始状态
        StateType State = NewFieldStart;

        for (int i = 0, size = text.size(); i < size; ++i) {
            const char& ch = text[i];

            switch (State) {
                case NewFieldStart: { // 新字段开始
                    if (ch == '"') {
                        State = QuotesField;
                    }
                    else if (ch == ',') {
                        Fields.push_back("");
                        State = FieldSeparator;
                    }
                    else if (ch == '\r' || ch == '\n') {
                        m_strErrorInfo = "语法错误:有空行";
                        State = Error;
                    }
                    else {
                        strField.push_back(ch);
                        State = NonQuotesField;
                    }
                }
                break;

                case NonQuotesField: { // 非引号字段
                    if (ch == ',') {
                        Fields.push_back(strField);
                        strField.clear();
                        State = FieldSeparator;
                    }
                    else if (ch == '\r') {
                        Fields.push_back(strField);
                        State = RowSeparator;
                    }
                    else {
                        strField.push_back(ch);
                    }
                }
                break;

                case QuotesField: { // 引号字段
                    if (ch == '"') {
                        State = QuoteInQuotesField;
                    }
                    else {
                        strField.push_back(ch);
                    }
                }
                break;

                case FieldSeparator: { // 字段分隔
                    if (ch == ',') {
                        Fields.push_back("");
                    }
                    else if (ch == '"') {
                        strField.clear();
                        State = QuotesField;
                    }
                    else if (ch == '\r') {
                        Fields.push_back("");
                        State = RowSeparator;
                    }
                    else {
                        strField.push_back(ch);
                        State = NonQuotesField;
                    }
                }
                break;

                case QuoteInQuotesField: { // 引号字段中的引号
                    if (ch == ',') {
                        // 引号字段闭合
                        Fields.push_back(strField);
                        strField.clear();
                        State = FieldSeparator;
                    }
                    else if (ch == '\r') {
                        // 引号字段闭合
                        Fields.push_back(strField);
                        State = RowSeparator;
                    }
                    else if (ch == '"') {
                        // 转义
                        strField.push_back(ch);
                        State = QuotesField;
                    }
                    else {
                        m_strErrorInfo = "语法错误: 转义字符 \" 不能完成转义 或 引号字段结尾引号没有紧贴字段分隔符";
                        State = Error;
                    }
                }
                break;

                case RowSeparator: { // 行分隔符字符1,回车
                    if (ch == '\n') {
                        m_content.push_back(Fields);
                        Fields = Row(); // Fields.clear();
                        strField.clear();
                        State = NewFieldStart;
                    }
                    else {
                        m_strErrorInfo = "语法错误: 行分隔用了回车 \\r。但未使用回车换行 \\r\\n ";
                        State = Error;
                    }
                }
                break;

                case Error: { // 语法错误
                    return;
                }
                break;

                default: break;
            }
        }
        // end for

        switch (State) {
            case NewFieldStart: {
                // Excel导出的CSV每行都以/r/n结尾。包括最后一行
            }
            break;

            case NonQuotesField: {
                Fields.push_back(strField);
                m_content.push_back(Fields);
            }
            break;

            case QuotesField: {
                m_strErrorInfo = "语法错误: 引号字段未闭合";
            }
            break;

            case FieldSeparator: {
                Fields.push_back("");
                m_content.push_back(Fields);
            }
            break;

            case QuoteInQuotesField: {
                Fields.push_back(strField);
                m_content.push_back(Fields);
            }
            break;

            case RowSeparator: {

            }
            break;

            case Error: {

            }
            break;

            default: break;
        }

        setHeader();
    }


    void Csv::setHeader()
    {
        m_header.clear();
        for (unsigned int i = 0; i < m_content[0].size(); i++) {
            m_header.push_back(m_content[0][i]);
        }
        for (unsigned int i = 0; i < m_content.size(); i++) {
            m_content[i].setHeader(&m_header);
        }
    }


    Row& Csv::operator[](unsigned int key)
    {
        if (key < m_content.size()) return m_content[key];
        throw "can't return this row (doesn't exist)";
    }
}

3、下载地址
CSVParser

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值