Skip to content

Instantly share code, notes, and snippets.

@hamsham
Created April 5, 2014 21:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hamsham/9998434 to your computer and use it in GitHub Desktop.
Save hamsham/9998434 to your computer and use it in GitHub Desktop.
Skeleton code for a command-Line argument tokenizer. It will input command-line arguments, convert them into a native data type, and place them into an std::vector as tuples.
/**
* Simple string-to-type tokenizing.
* This program can be used as skeleton code for creating a tokenizer for
* command-line arguments. It will convert values into a tuple-type where values
* can be extracted using their intended data type.
*
* Example:
* token +3.14159
* Results in two returned values:
* String: "token" (without quotes)
* Float: 3.14159
*
* Compile with:
* g++ -std=c++11 -Wall -Werror -Wextra -pedantic -pedantic-errors token.cpp -o token
*/
#include <iostream> // stds::cout
#include <utility> // std::move(...)
#include <string> // std::string
#include <cctype> // isDigit(...)
#include <vector> // std::vector
#include <cstdlib> // strtod(...), strtol(...)
enum data_t : int {
CHAR,
INT,
FLOAT,
STRING
};
struct tuple {
data_t type;
union {
char c;
int i;
float f;
const char* s;
};
std::string asString;
};
bool tokenize(std::string&& s, tuple& t) {
bool containsDecimal = false;
bool containsString = false;
bool containsNumber = false;
// Initialize the token
t.asString = std::move(s);
const std::string& str = t.asString;
// do an initial check to see if the token is a character
if (str.size() == 1 && isdigit(str[0]) == 0) {
t.type = data_t::CHAR;
t.c = str[0];
}
else {
// parse the token for its data type
for (unsigned i = 0; i < str.size(); ++i) {
// look for a number
if (isdigit(str[i]) != 0) {
containsNumber = true;
continue;
}
// determine if the first digit might be minus or plus sign
if (i == 0 && (str[0] == '-' || str[0] == '+')) {
continue;
}
if (str[i] == '.') {
// tokenize as a string if a decimal was already found
if (containsDecimal == true) {
containsString = true;
break;
}
containsDecimal = true;
}
else {
containsString = true;
break;
}
}
// convert the token into a tuple
if (containsString == true) {
t.type = data_t::STRING;
t.s = t.asString.c_str();
}
else if (containsDecimal == true) {
t.type = data_t::FLOAT;
t.f = (float) strtod(str.c_str(), nullptr);
}
else if (containsNumber == true) {
t.type = data_t::INT;
t.i = (int) strtol(str.c_str(), nullptr, 10);
}
else {
return false;
}
}
return true;
}
int main(int argc, const char** argv) {
std::vector<tuple> tokens{(unsigned)argc};
for (int i = 0; i < argc; ++i) {
tuple t;
bool wasTokenized = tokenize(std::move(std::string{argv[i]}), t);
if (wasTokenized == true) {
tokens[i] = t;
}
else {
std::cout << "ERROR: Unable to tokenize " << argv[i] << std::endl;
return -1;
}
}
for (const tuple& pToken : tokens) {
if (pToken.type == data_t::CHAR) {
std::cout << "CHAR --- " << pToken.c;
}
else if (pToken.type == data_t::INT) {
std::cout << "INT --- " << pToken.i;
}
else if (pToken.type == data_t::FLOAT) {
std::cout << "FLOAT --- " << pToken.f;
}
else {
std::cout << "STRING --- " << pToken.s;
}
std::cout << '\n';
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment