I'm using boost's regex library, and I'm finding that determining if a named match is found and then using that information is a little annoying. To detect a named match, I'd like to do this:
typedef boost::match_result<string::const_iterator> matches_t;
typedef matches_t::const_reference match_t;
boost::regex re("(?:(?<type1>aaaa)|(?<type2>bbbb)" /*...*/ "|(?<typeN>abcdefg)");
string str(SOME_STRING);
matches_t what;
boost::match_flag_type flags = boost::match_default;
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
if((match_t type1 = what["type1"]).matched)
{
// do stuff with type1
}
else if((match_t type2 = what["type2"]).matched)
{
// do stuff with type2
}
// ...
else if((match_t typeN = what["typeN"]).matched)
{
// do stuff with typeN
}
}
If that'd would work, that would be great. Scoping would be constrained to the if's body, memory can be used efficiently and it looks fairly clean. Sadly, it doesn't work as you cannot define a variable within a list. :(
This could have been a possibility:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
match_t found = what["type1"];
if(found.matched)
{
// do stuff with type1
}
else if((found = what["type2"]).matched)
{
// do stuff with type2
}
// ...
else if((found = what["typeN"]).matched)
{
// do stuff with typeN
}
}
But match_t is a const reference so it's not assignable. (tl;dr Also I don't know what the underlying type is and generally I don't really want to know as I'd prefer a more generic solution that I could use outside of this one example of regex. Even std::move() was used around what[...] it gets even more verbose and the documentation doesn't say that it uses move semantics for sub_match. All of this is moot of course due to the reason given in the first sentence of this paragraph.)
Another option is to do is this:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
match_t type1 = what["type1"];
if(type1.matched)
{
// do stuff with type1
}
else {
match_t type2 = what["type2"];
if(type2.matched)
{
// do stuff with type2
}
// ...
else {
match_t typeN = what["typeN"];
if((match_t typeN = what["typeN"]).matched)
{
// do stuff with typeN
}
}
// ...
}
}
}
Which I don't like due to deep nesting of braces.
Perhaps abusing a loop structure with break
s at the end of each if
body like this:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
do{
{
match_t type1 = what["type1"];
if(type1.matched)
{
// do stuff with type1
break;
}
}
{
match_t type2 = what["type2"];
if(type2.matched)
{
// do stuff with type2
break;
}
}
// ...
{
match_t typeN = what["typeN"];
if(typeN.matched)
{
// do stuff with typeN
break;
}
}
} while(0);
}
Which is better, but still not great. Using macros, much of the noise could be hidden from view. Like:
#define IF(declare, cond) do{{declare;if(cond){
#define ELSE_IF(declare, cond) break;}}{declare; if(cond){
#define ELSE break;}}{{
#define END_IF break;}}}while(0);
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
IF(match_t type1 = what["type1"], type1.matched)
{
// do stuff with type1
}
ELSE_IF(match_t type2 = what["type2"], type2.matched)
{
// do stuff with type2
}
// ...
ELSE_IF(match_t typeN = what["typeN"], typeN.matched)
{
// do stuff with typeN
}
END_IF
}
The braces are actually implied by the macros, but it makes for clearer reading by restating them.
One other option I can think of is to go into the boost::sub_match class and add a conversion function to convert that type to a bool who's return value would be that of the matched
member. Then I could declare a match_t variable in the if expression and it would automagically be converted to a boolean value by the if. I'm not sure if I'm there yet and it's not generic.
Stylistically, are the ones I propose good or bad (only the last 3 actually work, so I'd probably confine comments to them).
Also, does anyone have any better suggestions? Please state why you think they are better.
Syntax of structstruct structureName { dataType member1; dataType member2; ... }; For example, struct Person { char name[50]; int citNo; float salary; }; Here, a derived type struct Person is defined.
A structure is a collection of variables of same or different datatypes. It is useful in storing or using informations or databases. Example: An employee's record must show its salary, position, experience, etc. It all can be stored in one single variable using structures.
A struct in the C programming language (and many derivatives) is a composite data type (or record) declaration that defines a physically grouped list of variables under one name in a block of memory, allowing the different variables to be accessed via a single pointer or by the struct declared name which returns the ...
Structures (also called structs) are a way to group several related variables into one place. Each variable in the structure is known as a member of the structure. Unlike an array, a structure can contain many different data types (int, float, char, etc.).
It is generally recommended to avoid nested if
s - they make code harder to read. If there's nested if, it should probably replaced by a function call.
In your case, you need to use a loop.
your second example:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
match_t found = what["type1"];
if(found.matched)
{
// do stuff with type1
}
else if((found = what["type2"]).matched)
{
// do stuff with type2
}
// ...
else if((found = what["typeN"]).matched)
{
// do stuff with typeN
}
}
BEGS for a loop:
const char *types[] = {"type1", "type2", "typeN", 0};
for(const char **cur = types; *cur; cur++){
found = what[*cur];
if (found.matched){
//initiate robot uprising
break;
}
}
All your other examples (IMO) are a bad coding style. I prefer to keep loops and ifs short. If it doesn't fit into 20 lines of code, then it better be doing something very complicated (which is not your case). If it doesn't do anything complicated, it needs to be restructured.
You could do something like this (note this code is not tested against a compiler)
// create a map between match types and actions
std::map<std::string, std::function<match_t>> actions;
actions["type1"] = [&](match_t type) {...};
// iterate through the actions map and check each match type
for(auto kvp : actions)
{
match_t type = what[kvp.first];
if(type.matched)
{
// do stuff with this result
kvp.second(type);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With