Check if std::string is a valid uuid using boost - c++

I want to check if a given string is a valid UUID using boost.
This is what I have come up with by looking at the documentation on the boost website:
void validate_uuid(const std::string& value)
{
try
{
boost::uuids::string_generator stringGenerator;
(void)stringGenerator(value);
}
catch (const std::exception& ex)
{
// ...
}
}
However, this does not always work.
If I call the function with a string that is too short for a valid UUID, an exception is thrown as expected. But if I call the function with an invalid UUID (e.g. 00000000-0000-0000-0000-00000000000K) no exception is thrown.
Please can someone clarify why this is happening.
Also, I've seen the use of boost::lexical_cast to read a string as a UUID as posted here. I'm wondering if I should follow that approach. Any advice appreciated.

The code you had does nothing in terms of validation. Instead it generates a UUID based on the constant passed (like a hash function).
Looking closer I was mistaken. The missing bit of validation appears to be a check on version:
Live On Coliru
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/string_generator.hpp>
#include <iostream>
bool is_valid_uuid(std::string const& maybe_uuid, boost::uuids::uuid& result) {
using namespace boost::uuids;
try {
result = string_generator()(maybe_uuid);
return result.version() != uuid::version_unknown;
} catch(...) {
return false;
}
}
int main() {
std::string maybe_uuid;
std::cout << "Enter a UUID: ";
while (std::cin >> maybe_uuid)
{
boost::uuids::uuid result;
bool is_valid = is_valid_uuid(maybe_uuid, result);
std::cout << "\n'" << maybe_uuid << "' valid: " << std::boolalpha << is_valid << "\n";
if (is_valid)
std::cout << "Parsed value: " << result << "\n";
}
}
Sample output from Coliru: echo 00000000-0000-{0,4}000-0000-000000000000 $(uuidgen) "{$(uuidgen)}" | ./a.out:
Enter a UUID:
'00000000-0000-0000-0000-000000000000' valid: false
'00000000-0000-4000-0000-000000000000' valid: true
Parsed value: 00000000-0000-4000-0000-000000000000
'a2c59f5c-6c9b-4800-afb8-282fc5e743cc' valid: true
Parsed value: a2c59f5c-6c9b-4800-afb8-282fc5e743cc
'{82a31d37-6fe4-4b80-b608-c63ec5ecd578}' valid: true
Parsed value: 82a31d37-6fe4-4b80-b608-c63ec5ecd578

This seems way easier:
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <iostream>
#include <sstream>
int main()
{
std::string t1("01234567-89ab-cdef-0123-456789abcdef");
std::string t2("Test UUID");
boost::uuids::uuid u;
std::istringstream iss(t1);
iss >> u;
if (iss.good())
std::cerr << "'" << t1 << "' is a good UUID\n";
else
std::cerr << "'" << t1 << "' is not a good UUID\n";
iss.str(t2);
iss >> u;
if (iss.good())
std::cerr << "'" << t2 << "' is a good UUID\n";
else
std::cerr << "'" << t2 << "' is not a good UUID\n";
return 0;
}
$ g++ -I/usr/local/include -std=c++11 test1.cpp
$ a.out
'01234567-89ab-cdef-0123-456789abcdef' is a good UUID
'Test UUID' is not a good UUID

Since you already use boost you can use regex to check whether your string is a valid UUID
E.g for UUID version 4 you could use the following code
bool validate_uuid(const std::string& s)
{
static const boost::regex e("[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}");
return regex_match(s, e); // note: case sensitive now
}
(As mentioned in this answer and in the wiki there should be a valid version digit and another "special" digit).
Live on coliru.

Related

C++: converting wstring to double

Before converting wstring to double - how to validate it with regex? Java no problem, but C++ raising questions.. :)
I suppose you have a string and you want to know if it is a double or not. The following code does not use regular expressions. Instead it initializes a stringstream and reads a double from it. If the string starts with something non-numeric, then ss.fail() will be set. If it starts with a number, but does not read the whole string, then there's something non-numeric at the end of the string. So if everything went well and the string is really only a number, then ss.eof() && !ss.fail() will be true.
#include <iostream>
#include <sstream>
int main()
{
std::stringstream ss("123.456");
double mydouble;
ss >> mydouble;
if (ss.eof() && !ss.fail())
std::cout << "yay, success: " << mydouble << std::endl;
else
std::cout << "that was not a double." << std::endl;
return 0;
}
There's also std::wstringstream if you need to convert wide character strings.
You might also want to have a look at the boost libraries, especially at Boost.Lexical_Cast.
With this library you could do the following:
#include <boost/lexical_cast.hpp>
#include <iostream>
int main()
{
try
{
double mydouble = boost::lexical_cast<double>("123.456");
std::cout << "yay, success: " << mydouble << std::endl;
}
catch(const boost::bad_lexical_cast &)
{
std::cout << "that was not a double." << std::endl;
}
return 0;
}
Or maybe it is simpler to do that this way:
std::wstring strKeyValue = "147.sd44";
double value = (double) _wtof(strKeyValue.c_str());
And if strKeyValue==0 then it means it's not double.

handle empty string case extracting a string from std::istream

Using the following code to extract a string from a std::istream :
#include <sstream>
#include <iostream>
void parse(std::istream & is, std::string & out)
{
is >> out;
}
int main(int argc, char** argv)
{
if (argc>1)
{
std::istringstream is(argv[1]);
std::string out("__INIT__");
std::cout << "good:" << is.good() << " fail:"<< is.fail() << " eof:"<< is.eof() << " in_avail:"<< is.rdbuf()->in_avail() << " value:" << out << std::endl;
parse(is, out);
std::cout << "good:" << is.good() << " fail:"<< is.fail() << " eof:"<< is.eof() << " in_avail:"<< is.rdbuf()->in_avail() << " value:" << out << std::endl;
}
}
With a non-empty string the output looks like :
$./a.out "TEST"
good:1 fail:0 eof:0 in_avail:4 value:__INIT__
good:0 fail:0 eof:1 in_avail:0 value:TEST
With an empty string the output looks like :
$./a.out ""
good:1 fail:0 eof:0 in_avail:0 value:__INIT__
good:0 fail:1 eof:1 in_avail:0 value:__INIT__
Instead of this, I would expect :
good:1 fail:0 eof:0 in_avail:0 value:__INIT__
good:0 fail:0 eof:1 in_avail:0 value:
The operator>> does not extract an empty string. The result is the same with an empty string or and no data.
Any suggestion to handle this situation will be appreciated.
If you're using your parse function exclusively for extraction, you can simply make it out to be a check for an empty buffer. If there is, simply clear the string:
void parse(std::istream& is, std::string& out)
{
if (is.eof() || is.peek() == std::char_traits<char>::eof())
{
out.clear();
return;
}
is >> out;
}
There is no difference between an empty value and no value.
That's just your assumption, and it's not really true.
If you attempt to extract a string, it is expected that there are characters to extract. Before characters are available, it is impossible to perform any extraction, let alone one that results in extraction to a particular object.
This is entirely expected behaviour.
I guess your confusion stems from your prior check for argc > 1, but although the shell pretended ./myProgram "" had some argument, as far as your stream is concerned there is nothing in that argument.
If you wish to make your own handling for it, simply stick an if condition on is.fail() after the read.
#include <sstream>
#include <iostream>
int main(int argc, char** argv)
{
if (argc>1)
{
std::istringstream is(argv[1]);
std::string out;
is >> out;
if (is.fail()) {
std::cout << "Well, you gave me an argument, but it was empty, biatch!\n";
}
}
}
Don't bother checking is.eof(); it'll be set when you reached the end of input whether it contained any characters or not.

How to expand environment variables in .ini files using Boost

I have a INI file like
[Section1]
Value1 = /home/%USER%/Desktop
Value2 = /home/%USER%/%SOME_ENV%/Test
and want to parse it using Boost. I tried using Boost property_tree like
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini("config.ini", pt);
std::cout << pt.get<std::string>("Section1.Value1") << std::endl;
std::cout << pt.get<std::string>("Section1.Value2") << std::endl;
But it didn't expand the environment variable. Output looks like
/home/%USER%/Desktop
/home/%USER%/%SOME_ENV%/Test
I was expecting something like
/home/Maverick/Desktop
/home/Maverick/Doc/Test
I am not sure if it is even possible with boost property_tree.
I would appreciate any hint to parse this kind of file using boost.
And here's another take on it, using the old crafts:
not requiring Spirit, or indeed Boost
not hardwiring the interface to std::string (instead allowing any combination of input iterators and output iterator)
handling %% "properly" as a single % 1
The essence:
#include <string>
#include <algorithm>
static std::string safe_getenv(std::string const& macro) {
auto var = getenv(macro.c_str());
return var? var : macro;
}
template <typename It, typename Out>
Out expand_env(It f, It l, Out o)
{
bool in_var = false;
std::string accum;
while (f!=l)
{
switch(auto ch = *f++)
{
case '%':
if (in_var || (*f!='%'))
{
in_var = !in_var;
if (in_var)
accum.clear();
else
{
accum = safe_getenv(accum);
o = std::copy(begin(accum), end(accum), o);
}
break;
} else
++f; // %% -> %
default:
if (in_var)
accum += ch;
else
*o++ = ch;
}
}
return o;
}
#include <iterator>
std::string expand_env(std::string const& input)
{
std::string result;
expand_env(begin(input), end(input), std::back_inserter(result));
return result;
}
#include <iostream>
#include <sstream>
#include <list>
int main()
{
// same use case as first answer, show `%%` escape
std::cout << "'" << expand_env("Greeti%%ng is %HOME% world!") << "'\n";
// can be done streaming, to any container
std::istringstream iss("Greeti%%ng is %HOME% world!");
std::list<char> some_target;
std::istreambuf_iterator<char> f(iss), l;
expand_env(f, l, std::back_inserter(some_target));
std::cout << "Streaming results: '" << std::string(begin(some_target), end(some_target)) << "'\n";
// some more edge cases uses to validate the algorithm (note `%%` doesn't
// act as escape if the first ends a 'pending' variable)
std::cout << "'" << expand_env("") << "'\n";
std::cout << "'" << expand_env("%HOME%") << "'\n";
std::cout << "'" << expand_env(" %HOME%") << "'\n";
std::cout << "'" << expand_env("%HOME% ") << "'\n";
std::cout << "'" << expand_env("%HOME%%HOME%") << "'\n";
std::cout << "'" << expand_env(" %HOME%%HOME% ") << "'\n";
std::cout << "'" << expand_env(" %HOME% %HOME% ") << "'\n";
}
Which, on my box, prints:
'Greeti%ng is /home/sehe world!'
Streaming results: 'Greeti%ng is /home/sehe world!'
''
'/home/sehe'
' /home/sehe'
'/home/sehe '
'/home/sehe/home/sehe'
' /home/sehe/home/sehe '
' /home/sehe /home/sehe '
1 Of course, "properly" is subjective. At the very least, I think this
would be useful (how else would you configure a value legitimitely containing %?)
is how cmd.exe does it on Windows
I'm pretty sure that this could be done trivally (see my newer answer) using a handwritten parser, but I'm personally a fan of Spirit:
grammar %= (*~char_("%")) % as_string ["%" >> +~char_("%") >> "%"]
[ _val += phx::bind(safe_getenv, _1) ];
Meaning:
take all non-% chars, if any
then take any word from inside %s and pass it through safe_getenv before appending
Now, safe_getenv is a trivial wrapper:
static std::string safe_getenv(std::string const& macro) {
auto var = getenv(macro.c_str());
return var? var : macro;
}
Here's a complete minimal implementation:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
static std::string safe_getenv(std::string const& macro) {
auto var = getenv(macro.c_str());
return var? var : macro;
}
std::string expand_env(std::string const& input)
{
using namespace boost::spirit::qi;
using boost::phoenix::bind;
static const rule<std::string::const_iterator, std::string()> compiled =
*(~char_("%")) [ _val+=_1 ]
% as_string ["%" >> +~char_("%") >> "%"] [ _val += bind(safe_getenv, _1) ];
std::string::const_iterator f(input.begin()), l(input.end());
std::string result;
parse(f, l, compiled, result);
return result;
}
int main()
{
std::cout << expand_env("Greeting is %HOME% world!\n");
}
This prints
Greeting is /home/sehe world!
on my box
Notes
this is not optimized (well, not beyond compiling the rule once)
replace_regex_copy would do as nicely and more efficient (?)
see this answer for a slightly more involved 'expansion' engine: Compiling a simple parser with Boost.Spirit
using output iterator instead of std::string for accumulation
allowing nested variables
allowing escapes

Passing variable (array type) from function to "main" scope Type: std::tr1::match_results<std::string::const_iterator>

I would like to pass the variable from a function to the main scope which I'm calling, I'm trying to do like I use to do in C but it returns nothing.
I want to be able to output and deal with it after the return of the function
#include "StdAfx.h"
#include <regex>
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
std::tr1::match_results<std::string::const_iterator> match(std::string& regex, const std::string& ip,std::tr1::match_results<std::string::const_iterator> res)
{
const std::tr1::regex pattern(regex.c_str());
bool valid = std::tr1::regex_match(ip, res, pattern);
std::cout << ip << " \t: " << (valid ? "valid" : "invalid") << std::endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
return res;
}
int main()
{
string regex = "(\\d{1,3}):(\\d{1,3}):(\\d{1,3}):(\\d{1,3})";
string ip = "49:22:33:444";
std::tr1::match_results<std::string::const_iterator> res;
match(regex,ip.c_str(), res);
cout << "Result >" << res[1] << "< " << endl;
_getch(); return 0;
}
When I compile and run, The output is: "FIRST RES FOUND: 49
Result ><"
It's probably a really simple solution but what do I have to do to set it for my main can read it correctly as in: "Result >49<"
Thanks in advance. :)
Option 1: Use references:
void match(string& regex, const string& ip, tr1::match_results<string::const_iterator> & res)
{
const tr1::regex pattern(regex.c_str());
bool valid = tr1::regex_match(ip, res, pattern);
cout << ip << " \t: " << (valid ? "valid" : "invalid") << endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
}
Option 2: Return the result by value and store it:
tr1::match_results<string::const_iterator> match(string& regex, const string& ip)
{
tr1::match_results<string::const_iterator> res;
// ...
return res;
}
int main()
{
// ...
tr1::match_results<string::const_iterator> res = match(regex, ip);
}
On a separate note, there should be absolutely no need for all the c_str() calls, as <regex> has a perfectly functional std::string interface. Check the documentation for details, you just have to get a couple of typenames right.
Edit: Here are some basic examples on using std::string. There are equivalent constructions for std::wstring, char* and wchar_t*, but std::strings should be the most useful one.
Since <regex> support is still patchy, you should consider the TR1 and Boost alternatives, too; I provide all three and you can pick one:
namespace ns = std; // for <regex>
namespace ns = std::tr1; // for <tr1/regex>
namespace ns = boost; // for <boost/regex.hpp>
ns::regex r("");
ns::smatch rxres; // 's' for 'string'
std::string data = argv[1]; // the data to be matched
// Fun #1: Search once
if (!ns::regex_search(data, rxres, r))
{
std::cout << "No match." << std::endl;
return 0;
}
// Fun #2: Iterate over all matches
ns::sregex_iterator rt(data.begin(), data.end(), r), rend;
for ( ; rt != rend; ++rt)
{
// *rt is the entire match object
for (auto it = rt->begin(), end = rt->end(); it != end; ++it)
{
// *it is the current capture group; the first one is the entire match
std::cout << " Match[" << std::distance(rt->begin(), it) << "]: " << *it << ", length " << it->length() << std::endl;
}
}
Don't forget to handle exceptions of type ns::regex_error.
Pass in res by reference instead of by value. In other words, declare the parameter res as a reference instead of a value, i.e., type &res, not type res.

How do I check if a C++ std::string starts with a certain string, and convert a substring to an int?

How do I implement the following (Python pseudocode) in C++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(For example, if argv[1] is --foo=98, then foo_value is 98.)
Update: I'm hesitant to look into Boost, since I'm just looking at making a very small change to a simple little command-line tool (I'd rather not have to learn how to link in and use Boost for a minor change).
Use rfind overload that takes the search position pos parameter, and pass zero for it:
std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) { // pos=0 limits the search to the prefix
// s starts with prefix
}
Who needs anything else? Pure STL!
Many have misread this to mean "search backwards through the whole string looking for the prefix". That would give the wrong result (e.g. string("tititito").rfind("titi") returns 2 so when compared against == 0 would return false) and it would be inefficient (looking through the whole string instead of just the start). But it does not do that because it passes the pos parameter as 0, which limits the search to only match at that position or earlier. For example:
std::string test = "0123123";
size_t match1 = test.rfind("123"); // returns 4 (rightmost match)
size_t match2 = test.rfind("123", 2); // returns 1 (skipped over later match)
size_t match3 = test.rfind("123", 0); // returns std::string::npos (i.e. not found)
You would do it like this:
std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
foo_value = std::stoi(arg.substr(prefix.size()));
Looking for a lib such as Boost.ProgramOptions that does this for you is also a good idea.
Just for completeness, I will mention the C way to do it:
If str is your original string, substr is the substring you want to
check, then
strncmp(str, substr, strlen(substr))
will return 0 if str
starts with substr. The functions strncmp and strlen are in the C
header file <string.h>
(originally posted by Yaseen Rauf here, markup added)
For a case-insensitive comparison, use strnicmp instead of strncmp.
This is the C way to do it, for C++ strings you can use the same function like this:
strncmp(str.c_str(), substr.c_str(), substr.size())
If you're already using Boost, you can do it with boost string algorithms + boost lexical cast:
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
try {
if (boost::starts_with(argv[1], "--foo="))
foo_value = boost::lexical_cast<int>(argv[1]+6);
} catch (boost::bad_lexical_cast) {
// bad parameter
}
This kind of approach, like many of the other answers provided here is ok for very simple tasks, but in the long run you are usually better off using a command line parsing library. Boost has one (Boost.Program_options), which may make sense if you happen to be using Boost already.
Otherwise a search for "c++ command line parser" will yield a number of options.
Code I use myself:
std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
std::string argumentValue = argument.substr(prefix.size());
}
Nobody used the STL algorithm/mismatch function yet. If this returns true, prefix is a prefix of 'toCheck':
std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()
Full example prog:
#include <algorithm>
#include <string>
#include <iostream>
int main(int argc, char** argv) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
<< "Will print true if 'prefix' is a prefix of string" << std::endl;
return -1;
}
std::string prefix(argv[1]);
std::string toCheck(argv[2]);
if (prefix.length() > toCheck.length()) {
std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
<< "'prefix' is longer than 'string'" << std::endl;
return 2;
}
if (std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()) {
std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck << '"' << std::endl;
return 0;
} else {
std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"' << toCheck << '"' << std::endl;
return 1;
}
}
Edit:
As #James T. Huggett suggests, std::equal is a better fit for the question: Is A a prefix of B? and is slight shorter code:
std::equal(prefix.begin(), prefix.end(), toCheck.begin())
Full example prog:
#include <algorithm>
#include <string>
#include <iostream>
int main(int argc, char **argv) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
<< "Will print true if 'prefix' is a prefix of string"
<< std::endl;
return -1;
}
std::string prefix(argv[1]);
std::string toCheck(argv[2]);
if (prefix.length() > toCheck.length()) {
std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
<< "'prefix' is longer than 'string'" << std::endl;
return 2;
}
if (std::equal(prefix.begin(), prefix.end(), toCheck.begin())) {
std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck
<< '"' << std::endl;
return 0;
} else {
std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"'
<< toCheck << '"' << std::endl;
return 1;
}
}
With C++17 you can use std::basic_string_view & with C++20 std::basic_string::starts_with or std::basic_string_view::starts_with.
The benefit of std::string_view in comparison to std::string - regarding memory management - is that it only holds a pointer to a "string" (contiguous sequence of char-like objects) and knows its size. Example without moving/copying the source strings just to get the integer value:
#include <exception>
#include <iostream>
#include <string>
#include <string_view>
int main()
{
constexpr auto argument = "--foo=42"; // Emulating command argument.
constexpr auto prefix = "--foo=";
auto inputValue = 0;
constexpr auto argumentView = std::string_view(argument);
if (argumentView.starts_with(prefix))
{
constexpr auto prefixSize = std::string_view(prefix).size();
try
{
// The underlying data of argumentView is nul-terminated, therefore we can use data().
inputValue = std::stoi(argumentView.substr(prefixSize).data());
}
catch (std::exception & e)
{
std::cerr << e.what();
}
}
std::cout << inputValue; // 42
}
Given that both strings — argv[1] and "--foo" — are C strings, #FelixDombek's answer is hands-down the best solution.
Seeing the other answers, however, I thought it worth noting that, if your text is already available as a std::string, then a simple, zero-copy, maximally efficient solution exists that hasn't been mentioned so far:
const char * foo = "--foo";
if (text.rfind(foo, 0) == 0)
foo_value = text.substr(strlen(foo));
And if foo is already a string:
std::string foo("--foo");
if (text.rfind(foo, 0) == 0)
foo_value = text.substr(foo.length());
Starting with C++20, you can use the starts_with method.
std::string s = "abcd";
if (s.starts_with("abc")) {
...
}
text.substr(0, start.length()) == start
Using STL this could look like:
std::string prefix = "--foo=";
std::string arg = argv[1];
if (prefix.size()<=arg.size() && std::equal(prefix.begin(), prefix.end(), arg.begin())) {
std::istringstream iss(arg.substr(prefix.size()));
iss >> foo_value;
}
At the risk of being flamed for using C constructs, I do think this sscanf example is more elegant than most Boost solutions. And you don't have to worry about linkage if you're running anywhere that has a Python interpreter!
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
for (int i = 1; i != argc; ++i) {
int number = 0;
int size = 0;
sscanf(argv[i], "--foo=%d%n", &number, &size);
if (size == strlen(argv[i])) {
printf("number: %d\n", number);
}
else {
printf("not-a-number\n");
}
}
return 0;
}
Here's some example output that demonstrates the solution handles leading/trailing garbage as correctly as the equivalent Python code, and more correctly than anything using atoi (which will erroneously ignore a non-numeric suffix).
$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number
I use std::string::compare wrapped in utility method like below:
static bool startsWith(const string& s, const string& prefix) {
return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
C++20 update :
Use std::string::starts_with
https://en.cppreference.com/w/cpp/string/basic_string/starts_with
std::string str_value = /* smthg */;
const auto starts_with_foo = str_value.starts_with(std::string_view{"foo"});
In C++20 now there is starts_with available as a member function of std::string defined as:
constexpr bool starts_with(string_view sv) const noexcept;
constexpr bool starts_with(CharT c) const noexcept;
constexpr bool starts_with(const CharT* s) const;
So your code could be something like this:
std::string s{argv[1]};
if (s.starts_with("--foo="))
In case you need C++11 compatibility and cannot use boost, here is a boost-compatible drop-in with an example of usage:
#include <iostream>
#include <string>
static bool starts_with(const std::string str, const std::string prefix)
{
return ((prefix.size() <= str.size()) && std::equal(prefix.begin(), prefix.end(), str.begin()));
}
int main(int argc, char* argv[])
{
bool usage = false;
unsigned int foos = 0; // default number of foos if no parameter was supplied
if (argc > 1)
{
const std::string fParamPrefix = "-f="; // shorthand for foo
const std::string fooParamPrefix = "--foo=";
for (unsigned int i = 1; i < argc; ++i)
{
const std::string arg = argv[i];
try
{
if ((arg == "-h") || (arg == "--help"))
{
usage = true;
} else if (starts_with(arg, fParamPrefix)) {
foos = std::stoul(arg.substr(fParamPrefix.size()));
} else if (starts_with(arg, fooParamPrefix)) {
foos = std::stoul(arg.substr(fooParamPrefix.size()));
}
} catch (std::exception& e) {
std::cerr << "Invalid parameter: " << argv[i] << std::endl << std::endl;
usage = true;
}
}
}
if (usage)
{
std::cerr << "Usage: " << argv[0] << " [OPTION]..." << std::endl;
std::cerr << "Example program for parameter parsing." << std::endl << std::endl;
std::cerr << " -f, --foo=N use N foos (optional)" << std::endl;
return 1;
}
std::cerr << "number of foos given: " << foos << std::endl;
}
Why not use gnu getopts? Here's a basic example (without safety checks):
#include <getopt.h>
#include <stdio.h>
int main(int argc, char** argv)
{
option long_options[] = {
{"foo", required_argument, 0, 0},
{0,0,0,0}
};
getopt_long(argc, argv, "f:", long_options, 0);
printf("%s\n", optarg);
}
For the following command:
$ ./a.out --foo=33
You will get
33
Ok why the complicated use of libraries and stuff? C++ String objects overload the [] operator, so you can just compare chars.. Like what I just did, because I want to list all files in a directory and ignore invisible files and the .. and . pseudofiles.
while ((ep = readdir(dp)))
{
string s(ep->d_name);
if (!(s[0] == '.')) // Omit invisible files and .. or .
files.push_back(s);
}
It's that simple..
You can also use strstr:
if (strstr(str, substr) == substr) {
// 'str' starts with 'substr'
}
but I think it's good only for short strings because it has to loop through the whole string when the string doesn't actually start with 'substr'.
With C++11 or higher you can use find() and find_first_of()
Example using find to find a single char:
#include <string>
std::string name = "Aaah";
size_t found_index = name.find('a');
if (found_index != std::string::npos) {
// Found string containing 'a'
}
Example using find to find a full string & starting from position 5:
std::string name = "Aaah";
size_t found_index = name.find('h', 3);
if (found_index != std::string::npos) {
// Found string containing 'h'
}
Example using the find_first_of() and only the first char, to search at the start only:
std::string name = ".hidden._di.r";
size_t found_index = name.find_first_of('.');
if (found_index == 0) {
// Found '.' at first position in string
}
More about find
More about find_first_of
Good luck!
std::string text = "--foo=98";
std::string start = "--foo=";
if (text.find(start) == 0)
{
int n = stoi(text.substr(start.length()));
std::cout << n << std::endl;
}
Since C++11 std::regex_search can also be used to provide even more complex expressions matching. The following example handles also floating numbers thorugh std::stof and a subsequent cast to int.
However the parseInt method shown below could throw a std::invalid_argument exception if the prefix is not matched; this can be easily adapted depending on the given application:
#include <iostream>
#include <regex>
int parseInt(const std::string &str, const std::string &prefix) {
std::smatch match;
std::regex_search(str, match, std::regex("^" + prefix + "([+-]?(?=\\.?\\d)\\d*(?:\\.\\d*)?(?:[Ee][+-]?\\d+)?)$"));
return std::stof(match[1]);
}
int main() {
std::cout << parseInt("foo=13.3", "foo=") << std::endl;
std::cout << parseInt("foo=-.9", "foo=") << std::endl;
std::cout << parseInt("foo=+13.3", "foo=") << std::endl;
std::cout << parseInt("foo=-0.133", "foo=") << std::endl;
std::cout << parseInt("foo=+00123456", "foo=") << std::endl;
std::cout << parseInt("foo=-06.12e+3", "foo=") << std::endl;
// throw std::invalid_argument
// std::cout << parseInt("foo=1", "bar=") << std::endl;
return 0;
}
The kind of magic of the regex pattern is well detailed in the following answer.
EDIT: the previous answer did not performed the conversion to integer.
if(boost::starts_with(string_to_search, string_to_look_for))
intval = boost::lexical_cast<int>(string_to_search.substr(string_to_look_for.length()));
This is completely untested. The principle is the same as the Python one. Requires Boost.StringAlgo and Boost.LexicalCast.
Check if the string starts with the other string, and then get the substring ('slice') of the first string and convert it using lexical cast.