Reputation: 1
I have a string in the format <a,b>
, which represents an edge in a directed graph (a
is source and b
is target). a
and b
are also strings themselves (for example, a
can be "Square"
and b
is "Circle"
).
I need to build a function which extracts a
, and another function which extracts b
. So the signature will be:
string getSource(String edge); //will return b
string getTarget(String edge); //will return a
I am using the std::string
library to represent those strings.
I know that I need to find a way to find the ','
separating them in the middle of the string, and get rid of the '<'
and '>'
. But I couldn't find a function in std::string
that will help me to do that.
How would you go about on doing this?
Upvotes: 0
Views: 62
Reputation: 76305
This sounds like it belongs in a class whose constructor takes that std::string
argument and parses it.
class edge {
public:
edge(const std::string& str);
std::string source() const { return src; }
std::string target() const { return tgt; }
private:
std::string src;
std::string tgt;
};
edge::edge(const std::string& str) {
auto comma = std::find(std::begin(str), std::end(str), ',');
if (str.length() < 3 || comma == std::end(str) || str.front() != '<' || str.back() != '>')
throw std::runtime_error("bad input");
src = std::string(std::next(std::begin(str)), comma);
tgt = std::string(std::next(comma), std::prev(std::end(str)));
}
I wouldn't use a regular expression for such a simple parse. Regular expressions are expensive and highly overrated.
Upvotes: 0
Reputation: 169018
If you know for certain that the string is in the correct format, this is just a matter of using std::find
to locate the characters of interest and then constructing a new string from those iterators. For example:
std::string getSource(std::string const & edge) {
return {
std::next(std::find(std::begin(edge), std::end(edge), '<')),
std::find(std::begin(edge), std::end(edge), ',')
};
}
std::string getTarget(std::string const & edge) {
return {
std::next(std::find(std::begin(edge), std::end(edge), ',')),
std::find(std::begin(edge), std::end(edge), '>')
};
}
If the strings are not in the correct format then these functions could exhibit undefined behavior. This could be fixed trivially with the use of a helper function:
template <typename T>
std::string checkedRangeToString(T begin, T end) {
if (begin >= end) {
// Bad format... throw an exception or return an empty string?
return "";
}
return {begin, end};
}
std::string getSource(std::string const & edge) {
return checkedRangeToString(
std::next(std::find(std::begin(edge), std::end(edge), '<')),
std::find(std::begin(edge), std::end(edge), ',')
);
}
std::string getTarget(std::string const & edge) {
return checkedRangeToString(
std::next(std::find(std::begin(edge), std::end(edge), ',')),
std::find(std::begin(edge), std::end(edge), '>')
);
}
Upvotes: 0
Reputation: 60228
This seems to be a good use case for a regex:
std::regex sd {R"(<(.*),(.*)>)"};
and then your functions can be written as:
std::string getSource(std::string const & edge) {
std::smatch m;
std::regex_match(edge, m, sd);
return m[1].str();
}
and in getTarget
you would return m[2].str();
.
Upvotes: 1