標籤:c++ regex boost
有時候寫代碼時會遇到以下問題
假設有一個文字檔,其包含內容類別似於C語言,其中有一行如下格式的語句:
layout (local_size_x = a,local_size_y = b, local_size_z = c) in; |
其中用藍色標記出的部分(layout, local_size_x, local_size_y, local_size_z, in)為關鍵字,斜體字部分(a, b, c)為資料類型為unsigned int的數字,請編寫一個函數,用於從檔案中抽取出a, b, c的值,其中檔案名稱為輸入參數,該函數的返回值是抽取得到的a,b,c三個值。
例如,對於如下一個文字檔,程式期望的輸出是(16, 16, 1)
#version 430 core layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; void main(void) { imageStore(uTexture, ivec2(gl_GlobalInvocationID.xy), vec4(0, 0, 0, 0)); } |
在分析文本時,需要注意如下幾點:
a. 我們假設文本中有且只有一個layout語句用於定義local_size_x,local_size_y和local_size_z,且這個語句的文法沒有錯誤;
b. 使用者可以通過//或者/*…*/方法來注釋掉某些代碼;
c. 使用者可以使用#define來進行宏定義;
d. local_size_x,local_size_y,local_size_z的預設值都為1,在定義了local_size_x和local_size_y的前提下,可以省略local_size_z;或者在定義了local_size_x的前提下,可以省略local_size_y和local_size_z。
例如,分析如下文本的返回值應該為(32, 16, 1)。
#version 430 core #define LOCAL_X32 // layout (local_size_x = 16, local_size_y = 13, local_size_z = 2) in; layout (local_size_x = LOCAL_X, local_size_y = 16) in; void main(void) { imageStore(uTexture, ivec2(gl_GlobalInvocationID.xy), vec4(0, 0, 0, 0)); } |
用boost::string 寫了一個代碼,
#include <iostream>#include <fstream>#include <map>#include <vector>#include <boost/tuple/tuple.hpp>#include <boost/lexical_cast.hpp>#include <boost/algorithm/string.hpp>#include <boost/utility/string_ref.hpp>class CTest{public:CTest(int vX = 1, int vY = 1, int vZ = 1) : m_X(vX), m_Y(vY), m_Z(vZ) {}~CTest() {}//*********************************************************************************//FUNCTION:void parseText(const char* vFileName){std::vector<std::string> StrVec;preprocess(vFileName, StrVec);/*for (int i=0; i<StrVec.size(); ++i){std::cout << StrVec[i] << std::endl;}*/processLayout(StrVec);}//*********************************************************************************//FUNCTION:void printMember() const{std::cout << m_X << " " << m_Y << " " << m_Z << std::endl;}//*********************************************************************************//FUNCTION:boost::tuples::tuple<int, int, int> getValue() const{return boost::make_tuple(m_X, m_Y, m_Z);}private://*********************************************************************************//FUNCTION:void preprocess(const char* vFileName, std::vector<std::string>& voStrVec){std::ifstream Ifs(vFileName);if (!Ifs) {std::cout << "Can not open the file " << vFileName << std::endl;exit(-1);}std::string LineStr;while (getline(Ifs, LineStr)){if (LineStr.find("//") != std::string::npos){std::string::iterator End = LineStr.begin()+LineStr.find("//");if (LineStr.begin() != End) voStrVec.push_back(std::string(LineStr.begin(), End));}else if (LineStr.find("/*") != std::string::npos){while (getline(Ifs, LineStr)){if (LineStr.find("*/") != std::string::npos) break;}}else if (LineStr.size() > 0) voStrVec.push_back(LineStr);}Ifs.close();}//*********************************************************************************//FUNCTION:void processLayout(const std::vector<std::string>& vStrVec){std::map<std::string, int> DataMap;for (unsigned int i=0; i<vStrVec.size(); ++i){if (vStrVec[i].find("#define") != std::string::npos) processDefine(vStrVec[i], DataMap);else if (vStrVec[i].find("layout") != std::string::npos) processLayout(vStrVec[i], DataMap);}}//*********************************************************************************//FUNCTION:void processDefine(const std::string& vSorceString, std::map<std::string, int>& voDataMap){typedef boost::split_iterator<std::string::const_iterator> Split_String_Itearor;Split_String_Itearor Bgn, End;std::vector<std::string> StrVec;for (Bgn = boost::algorithm::make_split_iterator(vSorceString, boost::algorithm::token_finder(boost::is_any_of(" "))); Bgn != End; ++Bgn){ if ((*Bgn).size()>0) StrVec.push_back(std::string((*Bgn).begin(), (*Bgn).end()));}//for (int i=0; i<StrVec.size(); ++i)//{//std::cout << StrVec[i] << std::endl;//}voDataMap[StrVec[1]] = boost::lexical_cast<int>(StrVec[2]);}void processLayout(const std::string& vSorceString, std::map<std::string, int>& vDataMap){typedef boost::split_iterator<std::string::const_iterator> Split_String_Itearor;Split_String_Itearor Bgn, End;std::vector<std::string> StrVec;for (Bgn = boost::algorithm::make_split_iterator(vSorceString, boost::algorithm::token_finder(boost::is_any_of(" (,);="))); Bgn != End; ++Bgn){ if ((*Bgn).size()>0) StrVec.push_back(std::string((*Bgn).begin(), (*Bgn).end()));}/*for (int i=0; i<StrVec.size(); ++i){std::cout << "[" << StrVec[i] << "]";}std::cout << std::endl;*/if (StrVec.size() >= 4){if (StrVec[2][0] >= '0' && StrVec[2][1] <= '9'){m_X = boost::lexical_cast<int>(StrVec[2]);}else{if (vDataMap.find(StrVec[2]) == vDataMap.end()){std::cout << "somethind if wrong \n";exit(1);}m_X = vDataMap[StrVec[2]];}}if (StrVec.size() >= 6){if (StrVec[4][0] >= '0' && StrVec[4][0] <= '9'){m_Y = boost::lexical_cast<int>(StrVec[4]);}else{if (vDataMap.find(StrVec[4]) == vDataMap.end()){std::cout << "somethind if wrong \n";exit(1);}m_Y = vDataMap[StrVec[4]];}}if (StrVec.size() >= 8){if (StrVec[6][0] >= '0' && StrVec[6][1] <= '9'){m_Z = boost::lexical_cast<int>(StrVec[6]);}else{if (vDataMap.find(StrVec[6]) == vDataMap.end()){std::cout << "somethind if wrong \n";exit(1);}m_Z = vDataMap[StrVec[6]];}}}private:int m_X;int m_Y;int m_Z;};int main(){CTest Test;Test.parseText("test.txt");Test. printMember();getchar();return 0;}
不過這題可以用boost::regex 來寫
#include <string>#include <fstream>#include <iostream>#include <boost\regex.hpp>#include <boost\algorithm\string\split.hpp>#include <boost\algorithm\string\regex.hpp>#include <boost\algorithm\string\classification.hpp>//****************************************************************************************************************//FUNCTION:unsigned int convertString2Ui(const std::string& vString){unsigned int Value = 0;for (unsigned int i=0; i<vString.length(); i++){Value = Value*10 + vString.at(i)-'0';}return Value;}//****************************************************************************************************************//FUNCTION:void readContentFromFile(const char* vFileName, std::string& voContent){std::ifstream InFile(vFileName);char* pContent = NULL;if (InFile){InFile.seekg(0, InFile.end); unsigned int NumCharacter = unsigned int (InFile.tellg()); pContent = new char[NumCharacter+1];InFile.seekg(0, std::ios::beg);int i=0;while (!InFile.eof()){if(InFile.read(&pContent[i], sizeof(char))) i++;}pContent[i] = '\0';voContent = std::string(pContent);}delete[] pContent;}//****************************************************************************************************************//FUNCTION:void deleteComments(std::string& vioString){boost::regex CommentRegEx("(//.*?\\n)|(/\\*.*?(\\*)+/)");vioString = boost::regex_replace(vioString, CommentRegEx, "", boost::regex_constants::match_not_dot_newline);}//****************************************************************************************************************//FUNCTION:void replaceMacro(std::string& vioString){boost::smatch MacroString;boost::regex MacroRegex("^#define(\\s)+([a-zA-z_0-9\\(\\)]+)(\\s)+([a-zA-z_0-9\\(\\)]+)");std::string::const_iterator Start = vioString.begin();std::string::const_iterator End = vioString.end();std::vector<std::string> MacroSet, ValueSet;while (boost::regex_search(Start, End, MacroString, MacroRegex, boost::regex_constants::match_not_null|boost::regex_constants::match_not_dot_newline)){Start = MacroString[0].second;MacroSet.push_back(MacroString[2].str());ValueSet.push_back(MacroString[4].str());}_ASSERT(MacroSet.size() == ValueSet.size());for (unsigned int i=0; i<MacroSet.size(); i++){vioString = boost::regex_replace(vioString, boost::regex(MacroSet.at(i)), ValueSet.at(i));}}//****************************************************************************************************************//FUNCTION:void dumpNums(const std::string& vContent, unsigned int& voA, unsigned int& voB, unsigned int& voC){voA = voB = voC = 1;boost::regex MatchRegex("layout \\(local_size_x = ([0-9]+)(, local_size_y = ([0-9]+)(, local_size_z = ([0-9]+))?)?\\) in;");boost::smatch MatchString;boost::regex_search(vContent, MatchString, MatchRegex);voA = convertString2Ui(MatchString[1].str());if (!MatchString[3].str().empty()) {voB = convertString2Ui(MatchString[3].str());if (!MatchString[5].str().empty()) voC = convertString2Ui(MatchString[5].str());}}//****************************************************************************************************************//FUNCTION:void parseFile(const std::string& vFileName, unsigned int& voA, unsigned int& voB, unsigned int& voC){std::string Content;readContentFromFile(vFileName.c_str(), Content);deleteComments(Content);replaceMacro(Content);dumpNums(Content, voA, voB ,voC);}void installMemoryLeakDetector(){#if defined(DEBUG) | defined(_DEBUG)_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//_crtBreakAlloc = 955;#endif}int main(int argc, char** argv){installMemoryLeakDetector();_ASSERT(argc >= 2);const std::string FileName(argv[1]);unsigned int A = 0, B = 0, C = 0; parseFile(FileName, A, B, C);std::cout << A << " " << B << " " << C << std::endl;return 0;}