Probably the simplest way is just to use the standard member functions .find_first_of()
to find the first '('
and .find_last_of()
to find the last ')'
and then extract the .substr()
between them. For example:
#include <iostream>
int main (void) {
std::string input = "Hello(\"hey\",a1,a2,a3(a4()),1)";
size_t start = input.find_first_of ("("),
end = input.find_last_of (")");
if (start != std::string::npos && end != std::string::npos)
std::cout << input.substr (start+1, end-start-1) << '\n';
}
(you can add an additional validation that end > start
if you like)
Example Use/Output
$ ./bin/str_first_last_of_substr
"hey",a1,a2,a3(a4()),1
Note: it is probably better to use .find()
and .rfind()
in this case as @RemyLebeau suggests in the comments. The changes are as follows:
size_t start = input.find ("("),
end = input.rfind (")");
Multiple Patterns In Single String
As you changed the input string to contain multiple blocks to extract, the simply .find_first_of()
and .find_last_of()
will no longer work. Instead simply use .find()
, or simply iterate over each character in the strng. Keep a counter to balance the parenthesis. When you encounter an open-parenthesis, increment the counter. When you find a close-parenthesis, decrement the counter. When the counter reaches zero, extract the substring, e.g.
#include <iostream>
int main (void) {
std::string input = "bla bla bla bla Hello(\"hey\",a1,a2,a3(a4()),1) "
"bla bla bla bla Hello(\"as\",d,c,v(f()),f) bla bla bla";
size_t start = 0,
end = start;
int balance = 0;
for (size_t i = start; input[i]; i++) {
if (input[i] == '(') {
if (balance == 0)
start = end = i;
balance++;
}
else if (input[i] == ')') {
balance--;
if (balance == 0)
end = i;
}
if (start != end && balance == 0) {
std::cout << input.substr (start+1, end-start-1) << '\n';
start = end;
}
}
}
Example Use/Output
$ ./bin/str_first_last_of_substr2
"hey",a1,a2,a3(a4()),1
"as",d,c,v(f()),f
Extracting Only 1st Block After "Hello("
To extract only the first block of interest, you just need to limit the number of blocks you process. So you can simply keep a counter, initialized to zero, and after processing the first block, increment the counter, and add the non-zero counter as part of your for
loop exit clause, e.g.
#include <iostream>
int main (void) {
std::string input = "bla bla bla bla Hello(\"hey\",a1,a2,a3(a4()),1) "
"bla bla bla bla Hello(\"as\",d,c,v(f()),f) bla bla bla";
size_t start = 0,
end = start,
count = 0;
int balance = 0;
for (size_t i = 0; !count && input[i]; i++) {
if (input[i] == '(') {
if (balance == 0)
start = end = i;
balance++;
}
else if (input[i] == ')') {
balance--;
if (balance == 0)
end = i;
}
if (start != end && balance == 0) {
std::cout << input.substr (start+1, end-start-1) << '\n';
count++;
start = end;
}
}
}
Example Use/Output
$ ./bin/str_first_last_of_substr3
"hey",a1,a2,a3(a4()),1
Parsing information from strings is really simple once you make friends with it. The key is always (1) know what your current position is in the string, (2) know what you are looking for, and (3) once found, properly handle extracting what you need and reset for the next search, ... repeat until you run out of string or reach some other predefined exit condition :)
Look things over and let me know if you have further questions.