views:

2774

answers:

5

How do I do 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.)

+9  A: 

Using 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_cast) {
    // bad parameter
}

Like most boost libraries, string algorithm & lexical cast are header-only, there's nothing to link in.

Ferruccio
+1 for suggesting boost
Matt H
+7  A: 

You would do it like this:

   std::string prefix("--foo=");
   if (!arg.compare(0, prefix.size(), prefix))
      foo_value = atoi(arg.substr(prefix.size()).c_str());

Looking for a lib such as Boost.ProgramOptions that does this for you is also a good idea.

Thomas
The biggest problem with this is that `atoi("123xyz")` returns `123`, whereas Python's `int("123xyz")` throws an exception.
Tom
The workaround, we can do, is to a sscanf() and compare the result and the original, to decide whether to proceed or throw exception.
Roopesh Majeti
Or just replace `atoi` with `strtol` or `strtoll`, which lets us detect error conditions in the input value.
Tom
A: 
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.

blwy10
+3  A: 

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
Tom
A: 

I use the std::string::find_first_of() method when I need to parse items. I also use other std::string methods to span spaces and get to the value.

Thomas Matthews