用Cocos開發模型特效工具編輯器,跨Mac和windows,當中有個需求是讀取並解析excel文件,但網上的查找的例子幾乎都只能是在windows下面使用,再或者是命令行腳本之類的。於是,自己寫了一個非常輕量級的excel解析代碼,純cpp,除了依賴幾個cocos2d 方法(zip解壓和tinyxml2解析庫),不依賴任何系統API。 目前只能解析常見的表式結構(如果把excel當成word文檔使用就別看下面了),分享給大家,
如轉發還請注明出處,感謝。
為了保證mac和windows都可以跑過,所以去掉注釋,原諒我是VS菜鳥,當然代碼夠簡單不寫也能看懂。
getSheetArray返回的是excel的 行數組 ,因為c++里面難以實現動態類結構,所以不得已寫成這種方式,一般情況下該數據拿到后需要二次加工,你可以拿一個簡單的excel表格(比如道具物品表),測試打個斷點就知道有哪些數據結構。 我還有一個純js版本的,適合cocos2d-js使用,待日后完善了再丟出來。
// // Excel.h // 基於com.lipi.excel as3 版本設計,感謝lipi的源碼參考 // Created by howe on 15/5/5. // auto excel = new Excel(); // bool result = excel->parseExcelFile(filepath, 1); // std::vector<LineInfo> arr = std::move( excel->getSheetArray() ); // #ifndef __ModelEditor__Excel__ #define __ModelEditor__Excel__ #include <stdio.h> #include <vector> #include <map> struct LineInfo { int lineIndex; std::vector<std::string> array; }; class Excel { public: Excel(); bool parseExcelFile(const std::string &filepath,int sheetIndex); std::vector<LineInfo> getSheetArray(); private: std::vector<std::string> _getValueArray(); private: std::map<int,LineInfo> excelHash; std::string _excelFilePath; }; #endif /* defined(__ModelEditor__Excel__) */
Excel.cpp 實現部分
// // Excel.cpp // // Created by howe on 15/5/5. // // #include <iostream> #include <string> #include "Excel.h" #include "cocos2d.h" #include "external/tinyxml2/tinyxml2.h" using namespace tinyxml2; using namespace std; unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t *size) { return cocos2d::FileUtils::getInstance()->getFileDataFromZip(zipFilePath, filename, size); } void deleteNum( std::string &content) { string::iterator t = content.begin(); while(t != content.end()) { if(*t >= '0' && *t <= '9') { content.erase(t); } else { t++; } } } int getColIndex(std::string &content) { auto returnValue = 0; for (auto i =0; i < content.length(); i++) { char n = content[i]; auto cValue = n - 64; returnValue *= 26; returnValue += cValue; } return returnValue - 1; } Excel::Excel() :_excelFilePath("") { } bool Excel::parseExcelFile(const std::string &ilepath, int sheetIndex) { _excelFilePath = ilepath; excelHash.clear(); char xml_file[256] = {0}; sprintf(xml_file, "xl/worksheets/sheet%d.xml",sheetIndex+1); ssize_t size; auto fileData = getFileDataFromZip(_excelFilePath, xml_file, &size); if (!fileData) { CCLOG(ilepath.c_str(), "The excel file is not exist!"); return false; } auto valueArray = std::move(_getValueArray()); tinyxml2::XMLDocument doc; doc.Parse((const char*)fileData,size); XMLElement *root = doc.RootElement(); XMLElement * sheetDataElement = root->FirstChildElement("sheetData"); XMLElement * rowElement =sheetDataElement->FirstChildElement("row"); while (rowElement) { LineInfo lineInfo; auto rowIndex = atoi(rowElement->Attribute("r")) - 1; lineInfo.lineIndex = rowIndex; std::vector<std::string> &rowArray = lineInfo.array; auto cElement = rowElement->FirstChildElement("c"); while (cElement) { std::string cc = cElement->Attribute("r"); deleteNum(cc); auto colIndex = getColIndex( cc ); std::string t = ""; std::string v = ""; if (cElement->Attribute("t")) { t = cElement->Attribute("t"); } auto vElement = cElement->FirstChildElement("v"); if (vElement) { v = vElement->GetText(); } if (rowArray.size() < colIndex) { int len = rowArray.size(); for (auto i = 0;i < colIndex - len;i++) { rowArray.push_back(""); // } } if (t == "s") { rowArray.push_back(valueArray[atoi(v.c_str())]); } else { rowArray.push_back(v); } cElement = cElement->NextSiblingElement("c"); } auto bb = false; for (auto iii : rowArray) { if (iii.length() > 1) { bb = true; break; } } if (bb) { excelHash[rowIndex] = lineInfo; } rowElement = rowElement->NextSiblingElement("row"); } return true; } std::vector<std::string> Excel::_getValueArray() { std::vector<std::string> result; ssize_t size; auto fileData = getFileDataFromZip(_excelFilePath, "xl/sharedStrings.xml", &size); tinyxml2::XMLDocument doc; doc.Parse((const char*)fileData,size); XMLElement *root = doc.RootElement(); XMLElement *siElement = root->FirstChildElement("si"); while (siElement) { std::string temp = ""; auto tElement = siElement->FirstChildElement("t"); while (tElement) { temp = temp + tElement->GetText(); tElement = tElement->NextSiblingElement("t"); } result.push_back(temp); siElement = siElement->NextSiblingElement("si"); } return result; } std::vector<LineInfo> Excel::getSheetArray() { std::vector<LineInfo> result; for ( auto ite = excelHash.begin();ite != excelHash.end();ite++) { auto &lineInfo_ = ite->second; result.push_back(lineInfo_); } return result; }