C++正则表达式例子
给了策划配置公式的地方,需要将策划配置的公式文本转化为可执行的脚本代码:
比如:self->mHp*2+target->2mMp*GetHit()+ self_mon->4mDan/1000 ==> self:lf_mHp(0)*2+dst:lf_mMp(2)*GetHit()+ src:lf_mDan(4)/1000
意思就是
1 指针变量凡是含有self的都变为src,target的都替换为dst
2 调用的属性前面的系数要提取出来
3 属性可能是多种多样的,所以提取方法不能写死。
当时时间紧急,对正则表达式也不熟,按照字符串分割的方法实现了。
代码如下:
1 void TestFormula(std::string& for_text) 2 { 3 using std::string; 4 using std::vector; 5 string::size_type pos = 0; 6 string searchStr = "->"; 7 string replaceStr = "#"; 8 9 if (for_text.find(searchStr) == string::npos) 10 { 11 return; 12 } 13 14 while ( (pos = for_text.find(searchStr, pos)) != string::npos) 15 { 16 if ((for_text.size() >= pos + 2 && for_text[pos + 2] == 'm') || (for_text.size() >= pos + 3 && for_text[pos + 3] == 'm' && for_text[pos + 2] >= '0' && for_text[pos + 2] <= '9')) 17 { 18 for_text.replace(pos, searchStr.size(), replaceStr); 19 } 20 pos++; 21 } 22 23 vector<string> lVector; 24 vector<string> rVector; 25 int lastSplitIdx = 0; 26 string lastText(""); 27 for (string::size_type i = 0; i < for_text.size(); i++) 28 { 29 if (for_text[i] == '+' || for_text[i] == '-' || for_text[i] == '*' || for_text[i] == '/' 30 || for_text[i] == '#' || for_text[i] == '(' || for_text[i] == ')' || for_text[i] == ',') 31 { 32 if (for_text[i] == '#') 33 { 34 lastText = for_text.substr(lastSplitIdx, i - lastSplitIdx); 35 } 36 else 37 { 38 if (lastText.size() > 0) 39 { 40 lVector.push_back(lastText); 41 rVector.push_back(for_text.substr(lastSplitIdx, i - lastSplitIdx)); 42 } 43 lastText = ""; 44 } 45 lastSplitIdx = i + 1; 46 } 47 } 48 if (lastSplitIdx != for_text.size()) 49 { 50 if (lastText.size() > 0) 51 { 52 lVector.push_back(lastText); 53 rVector.push_back(for_text.substr(lastSplitIdx, lastText.size() - lastSplitIdx)); 54 } 55 } 56 57 if (lVector.size() == 0 || rVector.size() == 0 || lVector.size() != rVector.size()) 58 { 59 return; 60 } 61 62 pos = 0; 63 int parseIdx = 0; 64 while ( ( pos = for_text.find(replaceStr, pos)) != string::npos) 65 { 66 string leftStr = lVector.at(parseIdx); 67 string rightStr = rVector.at(parseIdx); 68 string oldStr = leftStr + replaceStr + rightStr; 69 string category = rightStr.substr(0, 1); 70 string ower = leftStr; 71 if (category == "0" || category == "1" || category == "2" || category == "3" || category == "4") 72 { 73 rightStr = rightStr.substr(1, rightStr.size()); 74 } 75 else 76 { 77 category = "0"; 78 } 79 if (leftStr.find("self", 0) != string::npos) 80 { 81 ower = "src"; 82 } 83 else if (leftStr.find("target", 0) != string::npos) 84 { 85 ower = "dst"; 86 } 87 string newStr = ower + ":lf_" + rightStr + "(" + category + ")"; 88 for_text.replace(pos - leftStr.size(), oldStr.size(), newStr); 89 parseIdx++; 90 pos++; 91 } 92 } 93 int main() 94 { 95 std::string text("self->mHp*2+target->2mMp*GetHit()+self_mon->4mDan/1000"); 96 std::cout << text.c_str() << std::endl; 97 TestFormula(text); 98 std::cout<<text.c_str()<<std::endl; 99 100 return 0; 101 }
运行结果:
颇费周折有木有~~~,还有很多临界状态需要检查,一不留神可能就踩到坑里了。
索性,看了看正则表达式,发现非常好用。代码少很多,结果一模一样。
1 void TestFormulaRegex(std::string& for_text) 2 { 3 using std::string; 4 std::regex pat("([A-Za-z_]+)->([0-4]*)(m[A-Za-z]+)"); 5 string::const_iterator startPos = for_text.begin(); 6 string::const_iterator endPos = for_text.end(); 7 std::smatch mat; 8 while (std::regex_search(startPos, endPos, mat, pat)) 9 { 10 string object(mat[1].first, mat[1].second); 11 string category(mat[2].first, mat[2].second); 12 string attrName(mat[3].first, mat[3].second); 13 if (category.compare("") == 0) 14 { 15 category = "0"; 16 } 17 if (object.find("self", 0) != string::npos) 18 { 19 object = "src"; 20 } 21 else if (object.find("target", 0) != string::npos) 22 { 23 object = "dst"; 24 } 25 string replaceStr(object + ":lf_" + attrName + "(" + category + ")"); 26 for_text.replace(mat[0].first, mat[0].second, replaceStr); 27 startPos = for_text.begin(); 28 endPos = for_text.end(); 29 } 30 }