请考虑以下C ++问题:
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
class ParseURL{
private:
int qualify; // 0 means we qualify
public:
string node;
string service;
bool primary;
bool health;
string epoch;
// methods
ParseURL(string URL);
~ParseURL();
};
ParseURL::ParseURL(string URL){
vector<string> g2 = {"node", "service", "primary", "health", "epoch"};
for (string tag : g2){
auto found = URL.find(tag);
if ( found != string::npos ){
auto cut_from = found + 1 + tag.size() ;
auto meh = URL.substr(cut_from, URL.substr(cut_from).find("&") );
// is there a way we can avoid these lines below?
if (tag.find("node",0) == 0){
this->node = meh;
} else if (tag.find("service",0) == 0 ){
this->service = meh;
} else if (tag.find("epoch",0) == 0) {
this->epoch = meh;
} else if (tag.find("health",0) == 0){
this->health = (meh == "OK");
} else if (tag.find("primary",0) == 0 ){
this->primary == (this->node == meh);
}
}
}
}
ParseURL::~ParseURL(){
cout << "Tearing Down the class\n";
}
int main(){
char req[] = "GET /register?node=hostrpi3&service=potatoservice&primary=node1&health=OK&epoch=1559345106 HTTP";
string Request = req;
Request = Request.substr(Request.find_first_of(" ") );
Request = Request.substr(0, Request.find(" HTTP"));
ParseURL *a = new ParseURL(Request);
cout.width(12);
cout << "a->node: " << a->node << endl;
cout.width(12);
cout << "a->service: " << a->service << endl;
cout.width(12);
cout << "a->epoch: " << a->epoch << endl;
cout.width(12);
cout << "a->health: " << a->health << endl;
cout.width(12);
cout << "a->primary: " << a->primary << endl;
delete(a);
return 0;
}
我需要基于URL查询字符串表示一个对象,所需的标记在矢量g2中表示,并且如您所见,我在这些标记中为ParseURL
制作了数据成员。
o / p看起来像:
a->node: hostrpi3
a->service: potatoservice
a->epoch: 1559345106
a->health: 1
a->primary: 0
Tearing Down the class
尽管此版本有效,但感觉可以大大改善。尽管Vector中包含了所有内容,但我还是对每个这些属性重复进行tag.find
。我希望一定有更好的方法。您能指出正确的方向吗?谢谢!
编辑1
谢谢,我按照以下建议更新了构造函数:
ParseURL::ParseURL(string URL){
char tags[10][100] = {"node", "service", "primary", "health", "epoch"};
int i = 0;
for (auto tag : tags){
auto found = URL.find(tag);
if ( found != string::npos ){
auto cut_from = found + 1 + strlen(tag);
auto tag_info = URL.substr(cut_from, URL.substr(cut_from).find("&") );
switch (i){
case 0:
this->node = tag_info;
break;
case 1:
this->service = tag_info;
break;
case 2:
this->primary = (this->node == tag_info);
break;
case 3:
this->health = (tag_info == "OK");
break;
case 4:
this->epoch = tag_info;
break;
}
}
i++;
}
}
例如bash提供了变量的间接引用-也就是说,一个变量可能包含另一个变量的名称:
$ cat indirect.sh
#!/bin/bash
values="value1 value2"
value1="this is value1"
value2="this is value2"
for i in $values; do
echo "$i has value ${!i}"
done
$ ./indirect.sh
value1 has value this is value1
value2 has value this is value2
我希望类似的情况也存在,但是,我在这里学到了宝贵的经验教训。谢谢!
答案 0 :(得分:2)
我相信这个问题可以分解:
regex为将URL键值对(参数)提取到映射中提供了紧凑而强大的解决方案:
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <regex>
using namespace std;
int main()
{
map<string, string> keyValues;
string s = "GET /register?node=hostrpi3&service=potatoservice&primary=node1&health=OK&epoch=1559345106 HTTP";
regex keyValueRegex("[?&](\\w+)=(\\w+)");
auto pairsBegin = std::sregex_iterator(s.begin(), s.end(), keyValueRegex);
auto pairsEnd = std::sregex_iterator();
for (std::sregex_iterator i = pairsBegin; i != pairsEnd; ++i)
{
std::smatch match = *i;
keyValues[match[1]] = match[2];
}
for (auto p : keyValues)
{
cout << p.first << " " << p.second << endl;
}
}
给出输出:
epoch 1559345106
health OK
node hostrpi3
primary node1
service potatoservice
另一种方法(用于非常精细的URL解析)是使用cpp-netlib库(建议用于Boost包含)。
答案 1 :(得分:1)
在我的示例中,我并不完全了解您要使用该间接寻址的内容,但是可以通过以下方式完成此操作:
vector<string> values{"value1", "value2"}
map<const string, const string> fields_and_values{{"value1", "this is value1"}, {"value2", "this is value2"}};
for (value: values)
cout << value << " have value " << fields_and_values[value] << endl;
此代码使您可以动态添加更多字段。如果您具有预定义的字段数,那么这是一个矫kill过正,而简单的数组就可以了。 即
array<const string, 2> values{"this is value1", "this is value2"};
for (int i = 0; i < 2; ++i)
cout << "value" << i << " have value " << values[i] << endl;
希望能回答您的问题。
关于您的代码的一般信息:
您为什么从vector<string>
转到char[10][100]
? (特别是当您只有5个字符串,而它们都不占用100个字符时?)array<string, 5>
是解决您的问题的方法。
此外,请勿使用new
和delete
。没有理由进行堆分配,只需使用ParseURL parse(request)
(即使有充分的理由,请使用{ {1}})。
最后,如果您不想多次遍历字符串以查找不同的关键字,则可以使用正则表达式。
答案 2 :(得分:1)
假设要保留不同的类成员(而不是一个键值存储),您可以 使用静态的字符串表和指向成员的指针:
vector<pair<string,string ParseURL::*>> keys={{"node",&ParseURL::node},…};
但这在这里不起作用,因为类型不同,并且每种处理方式也不相同。相反,对于这种几乎并行度来说,语法上的最佳选择通常是 lambda :
const auto get=[&URL](const string &tag) {
auto found = URL.find(tag);
if(found == string::npos) return "";
auto cut_from = found + 1 + tag.size() ;
return URL.substr(cut_from, URL.substr(cut_from).find("&") );
};
node=get("node");
service=get("service");
epoch=get("epoch");
health=get("health")=="OK";
primary=get("primary")==node;
此样式的优点是可以明确初始化health
和primary
。通过使用私有构造函数进行足够的扭曲,可以将其放入成员初始化器列表,这是更好的做法。