前言
输入的源码当做是字符串,我需要把其中的标识符、数字、复数、函数、关键字等识别出来。之前做的计算器改进版本时,用了两次匹配,第一次分割Token,第二次分类Token,但是我想让这个分类步骤快一点,如果能在第一次分割的时候得到分组信息也就能省略第二次匹配了!
$n,n>0
用regex_replace也能得到分组,但是其返回的是相同分组的结果的结合,返回的只有一个字符串。我也想过对这个字符串进行分割,如果再用正则就违反我的要求了!所以我试过用空格来进行分割,但是这个字符串有些结果间是空格,有些没有。
string result = regex_replace(str,reg,"$1");//返回匹配reg的第一个分组的内容
匹配结果
匹配结果放在smatch类里,迭代器的内容就是smatch类。
smatch 类的 size() 指的是分组个数,也就是正则中左括号的个数。
.str(n) 表示第n个分组的内容。n=0时表示总的匹配结果,不传入参数也是一样。
regex reg1("([a-zA-Z\\_]\\w*)|(,)|([\\+\\-\\*\\/\\^\\%\\(\\)])|(\\d+(\\.\\d+)?(e[\\+\\-]?\\d+)?)");
string str1 = "43+12 - Print(3,4)*7";
for (sregex_iterator it(str1.begin(), str1.end(), reg1), it_end; it != it_end; ++it) {
for (int i = 0; i < 8; ++i) {
cout << i << ">" << (*it).str(i) << "\t";
}
cout << endl;
}
运行结果
0>43 1> 2> 3> 4>43 5> 6> 7>
0>+ 1> 2> 3>+ 4> 5> 6> 7>
0>12 1> 2> 3> 4>12 5> 6> 7>
0>- 1> 2> 3>- 4> 5> 6> 7>
0>Print 1>Print 2> 3> 4> 5> 6> 7>
0>( 1> 2> 3>( 4> 5> 6> 7>
0>3 1> 2> 3> 4>3 5> 6> 7>
0>, 1> 2>, 3> 4> 5> 6> 7>
0>4 1> 2> 3> 4>4 5> 6> 7>
0>) 1> 2> 3>) 4> 5> 6> 7>
0>* 1> 2> 3>* 4> 5> 6> 7>
0>7 1> 2> 3> 4>7 5> 6> 7>
请按任意键继续. . .
从上面明显看出,不同的种类的子字符串的最大非空值的索引可以区分它们的种类!
我们只需要记录这个索引就行了,再根据正则的分组来分类不同的子字符串。
for (sregex_iterator it(str1.begin(), str1.end(), reg1), it_end; it != it_end; ++it) {
//cout << it->str() << ",len=" << it->length() <<","<< endl;
bool flag = false;
int j = 0, k = 0;
//cout << "size="<<(*it).size() << endl;
for (int i = 0; i < 7; ++i) {
if (i != 0) {
if ((*it).str(i) != "") {
flag = true; //当遇到非空的后,就不再计算空的个数
++k;
}
else {
if (!flag) ++j;
}
}
cout << i << ">" << (*it).str(i) << "\t";
}
cout << "\tindex=" << j + k << endl;
}
- 本来凌晨想写这篇说明C++里做正则分类还是搞二次匹配吧!因为一次匹配再搞方法得到分组信息的速度太慢,当时想的方法是给不同分组加上逐迹递增的括号这样的方法2333。早上把文章写了一半后晚上又测试了一下,发现其实不加多余的括号分组信息也显示出来了,而且正则的括号越多性能越低,大家要尽量少写括号!
- 同样为了性能,中括号中的\\+号也不要\\了,还有减号,点,问号,小括号,花括号,星号等在放入中括号后,都用原来的符号就行,不要加两个转义符。