@@ -48,96 +48,103 @@ bool KeyMatch(const std::string& key1, const std::string& key2) {
4848 return key1 == key2.substr (0 , pos);
4949}
5050
51+ // KeyGet returns the matched part
52+ // For example, "/foo/bar/foo" matches "/foo/*"
53+ // "bar/foo" will been returned
54+ std::string KeyGet (const std::string& key1, const std::string& key2) {
55+ size_t pos = key2.find (" *" );
56+
57+ if (pos == std::string ::npos)
58+ return " " ;
59+
60+ if (key1.length () > pos)
61+ if (key1.substr (0 , pos) == key2.substr (0 , pos))
62+ return key1.substr (pos, key1.length () - pos);
63+
64+ return " " ;
65+ }
66+
5167// KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
5268// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource"
5369bool KeyMatch2 (const std::string& key1, const std::string& key2) {
54- std::vector<std::string> key1_arr = Split (key1, " /" );
55- std::vector<std::string> key2_arr = Split (key2, " /" );
56-
57- bool res = true ;
58- for (int i = 0 ; i < key2_arr.size (); i++) {
59- if (i >= key1_arr.size ()) {
60- res = false ;
61- break ;
62- }
63- if (key1_arr[i] != key2_arr[i]) {
64- size_t index1 = key2_arr[i].find (" *" );
65- size_t index2 = key2_arr[i].find (" :" );
66- if (index1 != std::string::npos) {
67- if (index1 == 0 ) {
68- res = true ;
69- break ;
70- } else if (key1_arr[i].compare (key2_arr[i].substr (0 , index1))) {
71- res = false ;
72- break ;
73- } else
74- continue ;
75- }
76- if (index2 == 0 ) {
77- if (key1_arr[i] == " " || !key2_arr[i].substr (1 ).compare (" " )) {
78- res = false ;
79- break ;
80- } else
81- continue ;
82- }
83- res = false ;
84- break ;
85- } else
86- continue ;
70+ std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
71+ k2 = regex_replace (k2, std::regex (" (.*?):[^/]+(.*?)" ), " $1[^/]+$2" );
72+ k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
73+ k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
74+
75+ if (!k2.compare (" *" ))
76+ k2 = " (.*)" ;
77+
78+ return RegexMatch (key1, " ^" + k2 + " $" );
79+ }
80+
81+ // KeyGet2 returns value matched pattern
82+ // For example, "/resource1" matches "/:resource"
83+ // if the path_var == "resource", then "resource1" will be returned
84+ std::string KeyGet2 (const std::string& key1, const std::string& key2, const std::string& path_var) {
85+ std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
86+
87+ std::vector<std::string> keys;
88+ std::regex keys_regex (" :[^/]+" );
89+ for (std::sregex_iterator it (k2.begin (), k2.end (), keys_regex), end_it; it != end_it; ++it) {
90+ keys.push_back (it->str ());
8791 }
8892
89- if (key2_arr.size () < key1_arr.size ())
90- if (key2_arr[key2_arr.size () - 1 ] != " *" )
91- res = false ;
93+ k2 = regex_replace (k2, std::regex (" (.*?):[^/]+(.*?)" ), " $1([^/]+)$2" );
94+ k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
95+ k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
96+ if (!k2.compare (" *" ))
97+ k2 = " (.*)" ;
98+ k2 = " ^" + k2 + " $" ;
99+
100+ std::smatch values;
101+ std::regex_match (key1.begin (), key1.end (), values, std::regex (k2));
92102
93- return res;
103+ for (int i = 0 ; i < keys.size (); i++)
104+ if (!path_var.compare (keys.at (i).substr (1 )))
105+ return values[i + 1 ];
106+
107+ return " " ;
94108}
95109
96110// KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
97111// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}"
98-
99112bool KeyMatch3 (const std::string& key1, const std::string& key2) {
100- std::vector<std::string> key1_arr = Split (key1, " /" );
101- std::vector<std::string> key2_arr = Split (key2, " /" );
102-
103- bool res = true ;
104- for (int i = 0 ; i < key2_arr.size (); i++) {
105- if (i >= key1_arr.size ()) {
106- res = false ;
107- break ;
108- }
109- if (key1_arr[i] != key2_arr[i]) {
110- size_t index1 = key2_arr[i].find (" *" );
111- size_t index2 = key2_arr[i].find (" {" );
112- size_t index3 = key2_arr[i].find (" }" );
113- if (index1 != std::string::npos) {
114- if (index1 == 0 ) {
115- res = true ;
116- break ;
117- } else if (key1_arr[i].compare (key2_arr[i].substr (0 , index1))) {
118- res = false ;
119- break ;
120- } else
121- continue ;
122- }
123- if (index2 == 0 && index3 > 0 && index3 != std::string::npos) {
124- if (key1_arr[i] == " " || !key2_arr[i].substr (1 , key2_arr[i].length () - 2 ).compare (" " )) {
125- res = false ;
126- break ;
127- } else
128- continue ;
129- }
130- res = false ;
131- break ;
132- } else
133- continue ;
113+ std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
114+ k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1[^/]+$2" );
115+ k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
116+ k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
117+
118+ return RegexMatch (key1, " ^" + k2 + " $" );
119+ }
120+
121+ // KeyGet3 returns value matched pattern
122+ // For example, "project/proj_project1_admin/" matches "project/proj_{project}_admin/"
123+ // if the pathVar == "project", then "project1" will be returned
124+ std::string KeyGet3 (const std::string& key1, const std::string& key2, const std::string& path_var) {
125+ std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
126+
127+ std::vector<std::string> keys;
128+ std::regex keys_regex (" \\ {[^/]+?\\ }" );
129+ for (std::sregex_iterator it (k2.begin (), k2.end (), keys_regex), end_it; it != end_it; ++it) {
130+ keys.push_back (it->str ());
134131 }
135132
136- if (key2_arr.size () < key1_arr.size ())
137- if (key2_arr[key2_arr.size () - 1 ] != " *" )
138- res = false ;
133+ k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1([^/]+?)$2" );
134+ k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
135+ k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
136+ if (!k2.compare (" *" ))
137+ k2 = " (.*)" ;
138+ k2 = " ^" + k2 + " $" ;
139139
140- return res;
140+ std::smatch values;
141+ std::regex_match (key1.begin (), key1.end (), values, std::regex (k2));
142+
143+ for (int i = 0 ; i < keys.size (); i++)
144+ if (!path_var.compare (keys.at (i).substr (1 , keys.at (i).length () - 2 )))
145+ return values[i + 1 ];
146+
147+ return " " ;
141148}
142149
143150// KeyMatch4 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
@@ -146,56 +153,35 @@ bool KeyMatch3(const std::string& key1, const std::string& key2) {
146153// "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
147154// But KeyMatch3 will match both.
148155bool KeyMatch4 (const std::string& key1, const std::string& key2) {
149- std::vector<std::string> key1_arr = Split (key1, " /" );
150- std::vector<std::string> key2_arr = Split (key2, " /" );
156+ std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
157+
158+ std::vector<std::string> tokens;
159+ std::regex tokens_regex (" \\ {([^/]+)\\ }" );
160+ for (std::sregex_iterator it (k2.begin (), k2.end (), tokens_regex), end_it; it != end_it; ++it)
161+ tokens.push_back (it->str ());
162+
163+ k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1([^/]+)$2" );
164+ k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
165+ k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
166+ k2 = " ^" + k2 + " $" ;
167+ std::smatch matches;
168+ std::regex_match (key1.begin (), key1.end (), matches, std::regex (k2));
169+ if (matches.empty ())
170+ return false ;
171+ if (tokens.size () != matches.size () - 1 )
172+ throw " KeyMatch4: number of tokens is not equal to number of values" ;
173+
151174 std::map<std::string, std::string> tokens_matches;
152175
153- bool res = true ;
154- for (int i = 0 ; i < key2_arr.size (); i++) {
155- if (i >= key1_arr.size ()) {
156- res = false ;
157- break ;
158- }
159- if (key1_arr[i] != key2_arr[i]) {
160- size_t index1 = key2_arr[i].find (" *" );
161- size_t index2 = key2_arr[i].find (" {" );
162- size_t index3 = key2_arr[i].find (" }" );
163- std::string token = key2_arr[i].substr (1 , key2_arr[i].length () - 2 );
164- if (index1 != std::string::npos) {
165- if (index1 == 0 ) {
166- res = true ;
167- break ;
168- } else if (key1_arr[i].compare (key2_arr[i].substr (0 , index1))) {
169- res = false ;
170- break ;
171- } else
172- continue ;
173- }
174- if (index2 == 0 && index3 > 0 && index3 != std::string::npos) {
175- if (key1_arr[i] == " " || !token.compare (" " )) {
176- res = false ;
177- break ;
178- }
179- if (tokens_matches.find (token) == tokens_matches.end ()) {
180- tokens_matches.insert (std::pair<std::string, std::string>(token, key1_arr[i]));
181- continue ;
182- } else if (tokens_matches.at (token).compare (key1_arr[i])) {
183- res = false ;
184- break ;
185- } else
186- continue ;
187- }
188- res = false ;
189- break ;
190- } else
176+ for (int i = 0 ; i < tokens.size (); i++) {
177+ if (tokens_matches.find (tokens[i]) == tokens_matches.end ()) {
178+ tokens_matches.insert (std::pair<std::string, std::string>(tokens[i], matches[i + 1 ]));
191179 continue ;
180+ } else if (tokens_matches.at (tokens[i]).compare (matches[i + 1 ])) {
181+ return false ;
182+ }
192183 }
193-
194- if (key2_arr.size () < key1_arr.size ())
195- if (key2_arr[key2_arr.size () - 1 ] != " *" )
196- res = false ;
197-
198- return res;
184+ return true ;
199185}
200186
201187// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
0 commit comments