终极调教:字符串的终极调教

字符串的终极调教


情景再现:本人在使用别人开源的一个库进行程序编写时,有一些库里的信息无法通过合适的函数获取,只能通过技术手段强行获取。

下图是开源库的输出示例,虽然只有三行,但是因为数字和逗号紧连着,想把数字剥离出来还是要下一番功夫的。思路是:将其先输出到一个txt文件中,然后再读入,用字符串处理技术将其中的各种信息剥离出来。


第一步,数据输出为txt

gsNURBSinfo(gsMultiPatch<T> const& m_patch,gsMultiBasis<T> const& m_basis){// 先输出std::ofstream out_info("NURBSinfo.txt");out_info << m_basis.basis(0);out_info.close();// 再读入getKnotVectorInfo();}

这里将输出的程序写在构造函数里了(因为编程需要,此段代码只是从本人项目中冗长的代码中截取的一小段,看官无需考虑这个问题),数据读入为一个单独的函数。

一些本文用到的变量,定义在类里的,也可以不考虑,代码注释中会介绍

public:std::string basis_type;// 基函数的类型index_t nurbs_dim; // 基函数的维度,index_t是int的派生,可以看做是intindex_tnurbs_node;// 结点总数real_t tran_number; // 用于数据类型转换的局部变量,real_t是double的派生,可以看做是doubleIGAinfo info_iga;// 单个节点向量的信息,定义了一个对象vector<IGAinfo> igainfo; // 容纳所有的节点向量的容器//vector<string> basis_info;

第二步,读入数据,并拆解
首先来解析第一行,“TensorBSplineBasis: dim=2, size=36.”,
其中“TensorBSplineBasis:”这一串字符会因项目模型的不同而不同,需要保存下来;
另外注意到“dim=2,”这里的数字“2”后面还有一个“,”,共同构成了一个字符串,需要把数字“2”提取出来;
同样需要提取“size=36.”中的数字“36”。

// 打开刚才输出的txt文件std::ifstream info_in("NURBSinfo.txt");// 设置几个局部变量std::string line;std::stringstream ss_buff;std::string temps;// 拾取该行字符串数据getline(info_in, line);ss_buff.str("");ss_buff.str(line);// ===========================================// 第一行数据// std::string basis_type;// 类中定义的成员变量,原程序中不在此位置ss_buff >> basis_type;// “TensorBSplineBasis:”// ===========================================ss_buff >> temps; // “dim=2,”// 获取数值std::string dim_str;for (auto ce : temps)// 基于范围的for循环,遍历每一个字符{if (isdigit(ce)) // 如果是数字{dim_str += ce;// 把数字型的字符保存下来}}// 字符串类型转为数字类型的函数nurbs_dim = trans_str_to_any(dim_str);//dim_str是string型,nurbs_dim是int型// ===========================================ss_buff >> temps; // size=36.std::string size_strfor (auto cf : temps){if (isdigit(cf)){size_str += cf;}}nurbs_node = trans_str_to_any(size_str);// size_str是string型,nurbs_node是int型ss_buff.clear();}

在以上的过程中为了将字符串类型的数字转化为数字类型,定义了trans_str_to_any() 函数,函数的实现如下,这里使用的是函数模板,需要返回值是什么类型就可以是什么类型。类型转化主要是通过 stringstream 这个流实现的,真的很好用啊。

template<typename T>T gsNURBSinfo<T>::trans_str_to_any(std::string s_str){T res;std::stringstream Repeater;Repeater << s_str;//string型Repeater >> res; // 任意T类型,由目标返回值类型决定return res;}

然后来解析第二行,“ Direction 0: [ 0 0 0 0.25 0.5 0.75 1 1 1 ] (deg=2, size=9, minSpan=0.25, maxSpan=0.25)”
这一行要复杂得多,“[ ]”中的数据量根据模型的不同是变化的。最难的不是获取“[ ]”中的数据,而是获取“minSpan=0.25,”中的“0.25”,试想一下,你会怎么做,这是一个字符串,数字夹在了字符中间,可以使用 isdigit() 函数提取数字,但是“.”不是数字。看我操作

// 获取一行待处理的数据getline(info_in, line);// 使用关键字判断是不是需要的数据行if (line.find("Direction") != std::string::npos){ss_buff.str("");ss_buff.str(line);ss_buff >> temps;// Directionss_buff >> temps;//0:info_iga.knot_direction = knot_dir;// 提取“[ ]”中的数据ss_buff >> temps;// [ss_buff >> temps;// 0std::string judge_symbol("]");while(temps != judge_symbol) { // temps中如果不是"]"就循环tran_number = trans_str_to_any(temps); // tran_number是double型info_iga.knot_vector.push_back(tran_number);//info_iga.knot_vector是vector型ss_buff >> temps;// 依次是0 0 0.25 0.5 0.75 1 1 1 ]}// =============================================ss_buff >> temps; // (deg=2,std::string dig_str;for (auto ca : temps){// 提取数字2if (isdigit(ca)){dig_str += ca;}}info_iga.knot_degree = trans_str_to_any(dig_str);// info_iga.knot_degree是int型// ============================================ss_buff >> temps; // size=9,std::string siz_str;for (auto cb : temps){// 提取数字9if (isdigit(cb)){siz_str += cb;}}info_iga.knot_size = trans_str_to_any(siz_str);// ============================================ss_buff >> temps; // minSpan=0.25,std::string mins_str;for (char cc : temps){// 提取数字0.25if (isdigit(cc) || cc == '.'){mins_str += cc;}}info_iga.knot_minSpan = trans_str_to_any(mins_str);// ===========================================ss_buff >> temps; // maxSpan=0.25)std::string maxs_str;for (char cd : temps){// 提取数字0.25if (isdigit(cd) || cd == '.'){maxs_str += cd;}}info_iga.knot_maxSpan = trans_str_to_any(maxs_str);// ===========================================ss_buff.clear();igainfo.push_back(info_iga);info_iga.initialize();++knot_dir;}

第三行和第二行的操作是完全一致的。
可以输出一下结果

// gsInfo是cout的派生gsInfo << basis_type << " ";gsInfo << "dim=" << nurbs_dim << ", ";gsInfo << "size=" << nurbs_node << ".\n";for (index_t j = 0; j < igainfo.size(); ++j){gsInfo << " Direction " << j << ": [ ";for (index_t k = 0; k < igainfo[j].knot_vector.size(); ++k){gsInfo << igainfo[j].knot_vector[k] << " ";}gsInfo << "] (";gsInfo << "deg=" << igainfo[j].knot_degree<< ", size=" << igainfo[j].knot_size<< ", minSpan=" << igainfo[j].knot_minSpan<< ", maxSpan=" << igainfo[j].knot_maxSpan;gsInfo << ")\n";}

看一下效果


以下是完整程序,顺序上与前文讲的不太一样。

template < class T>void gsNURBSinfo<T>::getKnotVectorInfo(){std::ifstream info_in("NURBSinfo.txt");std::string line;std::stringstream ss_buff;std::string temps;index_t knot_dir = 0;while (!info_in.eof()){getline(info_in, line);if (line.find("Direction") != std::string::npos){ss_buff.str("");ss_buff.str(line);ss_buff >> temps;// Directionss_buff >> temps;//0:info_iga.knot_direction = knot_dir;// 节点向量ss_buff >> temps;// [ss_buff >> temps;// 0std::string judge_symbol("]");while(temps != judge_symbol){tran_number = trans_str_to_any(temps);info_iga.knot_vector.push_back(tran_number);//节点向量ss_buff >> temps;// 0 0 1 1 1 ]}// =============================================ss_buff >> temps; // (deg=2,std::string dig_str;for (auto ca : temps){if (isdigit(ca)){dig_str += ca;}}info_iga.knot_degree = trans_str_to_any(dig_str);// ============================================ss_buff >> temps; // size=9,std::string siz_str;for (auto cb : temps){if (isdigit(cb)){siz_str += cb;}}info_iga.knot_size = trans_str_to_any(siz_str);// ============================================ss_buff >> temps; // minSpan=0.25std::string mins_str;//char m_dot('.');for (char cc : temps){if (isdigit(cc) || cc == '.'){mins_str += cc;}}info_iga.knot_minSpan = trans_str_to_any(mins_str);// ===========================================ss_buff >> temps; // maxSpan=0.25)std::string maxs_str;for (char cd : temps){if (isdigit(cd) || cd == '.'){maxs_str += cd;}}info_iga.knot_maxSpan = trans_str_to_any(maxs_str);ss_buff.clear();igainfo.push_back(info_iga);info_iga.initialize();//igainfo[knot_dir]=(info_iga);++knot_dir;}else if (!line.empty()){ // TensorBSplineBasis: dim=2, size=36.ss_buff.str("");ss_buff.str(line);ss_buff >> basis_type;// TensorBSplineBasis:// ===========================================ss_buff >> temps; // dim=2,// 获取数值std::string dim_str;for (auto ce : temps){if (isdigit(ce)) // 如果是数字{dim_str += ce;}}nurbs_dim = trans_str_to_any(dim_str);// ===========================================ss_buff >> temps; // size=4.std::string size_str;for (auto cf : temps){if (isdigit(cf)){size_str += cf;}}nurbs_node = trans_str_to_any(size_str);ss_buff.clear();}}gsInfo << basis_type << " ";gsInfo << "dim=" << nurbs_dim << ", ";gsInfo << "size=" << nurbs_node << ".\n";for (index_t j = 0; j < igainfo.size(); ++j){gsInfo << " Direction " << j << ": [ ";for (index_t k = 0; k < igainfo[j].knot_vector.size(); ++k){gsInfo << igainfo[j].knot_vector[k] << " ";}gsInfo << "] (";gsInfo << "deg=" << igainfo[j].knot_degree<< ", size=" << igainfo[j].knot_size<< ", minSpan=" << igainfo[j].knot_minSpan<< ", maxSpan=" << igainfo[j].knot_maxSpan;gsInfo << ")\n";}}// 字符串转换为数字的函数模板template<typename T>T gsNURBSinfo<T>::trans_str_to_any(std::string s_str){T res;std::stringstream Repeater;Repeater << s_str;Repeater >> res;return res;}}

相关推荐

相关文章