I want to parse a given string using strtok - but using it twice. String to parse: "x=2;y=30". Desired output: An array of strings containing [x,y] and an array of string containing [2,30]. Meaning, I want to first use ";" as a delimiter, then using "=" as a delimiter. How can I do that - in cpp?
-
Hello. Show us your code to see what is your blocking point – Bruno Nov 12 '19 at 11:26
-
Do you have to use `strtok`? [boost::string::split](https://theboostcpplibraries.com/boost.stringalgorithms#ex.stringalgorithms_11) or [std::regex](https://en.cppreference.com/w/cpp/regex) might be easier – Alan Birtles Nov 12 '19 at 11:31
1 Answers
In C++, I wouldn't use std::strtok()
. std::string
provides nice find
methods in multiple flavors, e.g. std::string::find_first_of()
.
As I couldn't resist to fiddle with the ancient strtok()
, a little demo for all that:
#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
int main()
{
char input[] = "x=2;y=30";
std::vector<char*> leftHandSides, rightHandSides;
for (char *in = input;;) {
char *lhs = strtok(in, "=");
in = nullptr;
if (!lhs) break;
char *rhs = strtok(in, ";");
if (!rhs) break;
leftHandSides.push_back(lhs);
rightHandSides.push_back(rhs);
}
for (size_t i = 0, n = rightHandSides.size(); i < n; ++i) {
std::cout << leftHandSides[i] << '=' << rightHandSides[i] << '\n';
}
}
Output:
x=2
y=30
Notes:
strtok()
has to be called with a pointer to buffer (to tokenize) for the first time, and with a 0-pointer for further results (of same buffer). Hence, thechar *in = input;
which is overridden afterchar *lhs = strtok(in, "=");
within = nullptr;
. It is important that this is done in the first iteration. That it happens in all other iterations as well is tolerated as it doesn't cause harm. (I could've checked with an additionalif
but hadn't won anything with this.)strtok()
modifies the input string. Hence, I usedchar input[] = "x=2;y=30";
intentional.
(Withconst char *input = "x=2;y=30";
, I would've made code with U.B.)
Finally, a variant using std::istringstream
and std::getline()
instead of std::strtok()
:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::string input = "x=2;y=30";
std::vector<std::string> leftHandSides, rightHandSides;
for (std::istringstream in(input);;) {
std::string lhs, rhs;
if (!std::getline(in, lhs, '=')
|| !std::getline(in, rhs, ';')) break;
leftHandSides.push_back(lhs);
rightHandSides.push_back(rhs);
}
for (size_t i = 0, n = rightHandSides.size(); i < n; ++i) {
std::cout << leftHandSides[i] << '=' << rightHandSides[i] << '\n';
}
}
Output:
x=2
y=30

- 19,528
- 6
- 28
- 56
-
The second variant works very well, about strtok(), you were right. Thanks! – Sarah De-Paz Nov 12 '19 at 12:37
-
1@SarahDe-Paz My first reflex was to use an outer loop to separate assignments and an inner part to separate LHS from RHS. But then I realized that the separators can be changed for every call of `strtok()` (even for the same input buffer). ;-) – Scheff's Cat Nov 12 '19 at 12:41