402

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).

Parker
  • 7,244
  • 12
  • 70
  • 92
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173

24 Answers24

790

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)
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Ludovic Aubert
  • 9,534
  • 4
  • 16
  • 28
  • 3
    @sweisgerber.dev, I'm confused on your first contention. The return value from `find` will only be zero if `titi` is at the *start* of the string. If it's found somewhere else, you'll get a non-zero return value and, if it's not found, you'll get `npos` which is also non-zero. Assuming I'm right, I'd prefer this answer since I don't have to bring in any non-standard stuff (yes, I know Boost is everywhere, I'd just prefer core C++ libs for simple stuff like this). – paxdiablo Jun 27 '17 at 02:29
  • @paxdiablo: you are right, it does indeed check if it starts with `titi`, but the conversion part is missing. – sweisgerber.dev Jun 27 '17 at 09:07
  • 3
    Do we have any evidence that this is optimized in most compilers? I don't find elsewhere mentioning either "find" or "rfind" optimization is common practice based on the return value it's checking against. – Superziyi Mar 26 '19 at 18:49
  • 10
    @alcoforado "rfind will start from the back of the string ..." No, that only applies to the overload of `rfind()` that does not take a `pos` parameter. If you use the overload that does take a `pos` parameter then it will not search the whole string, only that position and earlier. (Just like regular `find()` with `pos` parameter only looks in that position or later.) So if you pass `pos == 0`, as shown in this answer, then it will literally only consider for matches at that one position. That was already explaining in both the answer and comments. – Arthur Tacca Jun 01 '20 at 14:08
  • 2
    `that position or earlier` is the important phrase here. – Vishal Sahu Sep 27 '21 at 18:59
  • 2
    To instead find if a string ends with another string, you can do `s.find("toto", s.length() - 4) != std::string::npos`. Replace the number 4 with the length of the suffix you are looking for. – BlueStaggo Aug 29 '22 at 17:39
  • I think it's painful that this function was omitted and you need 1) StackOverflow and 2) a whole explanation of the intrinsics of s.rfind() to get a working answer. The first thing that itches in my case is to put this method in a library. Glaring omission in STL. Thanks for the answer though. ;-) – Ruud van Gaal Jan 03 '23 at 08:58
205

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.

Kostas
  • 4,061
  • 1
  • 14
  • 32
Thomas
  • 10,358
  • 4
  • 27
  • 35
  • 11
    The biggest problem with this is that `atoi("123xyz")` returns `123`, whereas Python's `int("123xyz")` throws an exception. – Tom Dec 10 '09 at 03:31
  • 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 Dec 10 '09 at 06:20
  • 1
    Or just replace `atoi` with `strtol` or `strtoll`, which lets us detect error conditions in the input value. – Tom Dec 12 '09 at 00:43
  • 1
    This is better solution than the `rfind` one which depends on optimization to work. – Calmarius Sep 19 '19 at 15:19
  • 2
    @Calmarius the `rfind` solution does not depend on any optimization. `rfind`'s behavior by definition is to only look at a single index when given `pos=0`, hence it is always an efficient check. Which syntax is more pleasant is a matter of preference. – Yuval Sep 11 '20 at 00:26
  • @Tom You said `atoi` -- did you mean `atoi` or `stoi`? – Raleigh L. Sep 29 '22 at 05:29
  • @RaleighL. I originally used `atoi` in my answer, but an editor replaced it with the more modern `std::stoi`. Tom's comment remains valid with `stoi`. – Thomas Sep 30 '22 at 07:04
  • Looking for a lib like Boost to check whether a string has a certain prefix? This is not a good idea! – Johannes Overmann Dec 16 '22 at 10:13
170

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())
Felix Dombek
  • 13,664
  • 17
  • 79
  • 131
  • 18
    indeed, everyone seems to just go "use boost" and i for one am thankful for an stl or OS library version – Force Gaia Apr 25 '18 at 10:44
  • 2
    Yes. However, it assumes the string has no null characters in it. If it is not the case - one should use ```memcmp()``` – Avishai Y Aug 14 '19 at 06:54
  • 2
    why would anyone use anything other than this simple beautiful solution? – Adham Zahran Oct 15 '19 at 12:43
  • 1
    @AvishaiY `it assumes the string has no null characters in it.` That is as much of an assumption as assuming that an ìnt` does not contain the value "-0.5" - C-string contains exactly a Single null-character as the end-marker. It is by definition NOT a C-string if it contains a \0 at any other position. – ABaumstumpf Jan 25 '23 at 08:38
95

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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • 2
    "boost::algorithm::starts_with" instead of "boost::starts_with" ? – cyrilchampier Aug 08 '12 at 09:43
  • @nerith: Seems they both work. I've always used the shorter form. – Ferruccio Aug 08 '12 at 10:55
  • 3
    **boost::starts_with and boost::algorithm::starts_with are the same thing.** If you look at the end of this file https://svn.boost.org/svn/boost/trunk/boost/algorithm/string/predicate.hpp you will see this: **// pull names to the boost namespace using algorithm::starts_with; [...]** – Alex Bitek Dec 14 '12 at 12:18
  • 134
    Pulling in huge dependencies for a string prefix check is like shooting birds with canons. – Tobi May 29 '16 at 17:27
  • 176
    "Use Boost" is always the wrong answer when someone asks how to do a simple string operation in C++. – Glenn Maynard Aug 21 '16 at 01:20
  • 100
    minus 1 for suggesting Boost – uglycoyote Oct 27 '16 at 22:51
  • 48
    Using boost here is right, if you already use boost in your project. – Alex Che May 12 '17 at 09:30
  • 3
    Using boost for this is wrong if this is the reason for which you would decide to link boost in the first place, if you are already using boost for other reasons I don't see why this would be huge a problem. – qwattash Jan 30 '18 at 01:57
  • 29
    The answer is prefixed with "If you're using Boost...". Clearly this is the right answer "...if you're using Boost". If not, look the suggestion by @Thomas – NuSkooler Feb 16 '18 at 21:44
  • 3
    Boost is always a solution if you use C++. There's no need to reinvent the wheel when there's no need to do it. We work, we are not doing homework assigments. – Jepessen Nov 25 '20 at 09:23
  • 4
    Boost is not a BIG library.. is a set of libraries big and smalls. If a small boost library can solve the problem I don't see the reason to avoid it. – Jepessen Jan 20 '21 at 15:15
90

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());
}
Huseyin Yagli
  • 9,896
  • 6
  • 41
  • 50
  • 3
    the most concise and only depends on std::string, except remove the optional and misleading argument.size() at the end of the final substr. – Ben Bryant Apr 06 '12 at 15:50
  • @ben-bryant: Thanks for the heads up. Didn't know it was optional. – Huseyin Yagli Apr 24 '12 at 22:07
  • 20
    Using `substr` leads to unnecessary copying. The `str.compare(start, count, substr)` method used in [Thomas' answer](http://stackoverflow.com/a/1878038/481061) is more efficient. [razvanco13's answer](http://stackoverflow.com/a/8596924/481061) has another method which avoids copying by using `std::equal`. – Felix Dombek Sep 25 '13 at 18:57
  • 4
    @HüseyinYağlı `Thomas uses atoi which is only for windows` Huh? `atoi` has been a C standard library function since... ever. In point of fact, `atoi` is bad- not because it's Windows-specific- but because it's (1) C, not C++, and (2) deprecated even in C (you should be using `strtol` or one of the other, related functions. Because `atoi` has no error handling. But, again, that's only in C, anyway). – Parthian Shot Nov 03 '15 at 03:10
54

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;
  }
}
matiu
  • 7,469
  • 4
  • 44
  • 48
39

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
}
Roi Danton
  • 7,933
  • 6
  • 68
  • 80
  • 1
    @RolandIllig No, `std::atoi` is completely fine. It throws exceptions on bad input (which is handled in this code). Did you have something else in mind? – Roi Danton Oct 16 '19 at 12:09
  • Are you talking about the `atoi` from ``? The [documentation says](http://www.cplusplus.com/reference/cstdlib/atoi/) "it never throws exceptions". – Roland Illig Oct 16 '19 at 18:47
  • @RolandIllig I'm referring to your first comment. It seems, you are mistakenly talking about `atoi` instead of `std::atoi`. The first is unsafe to use, while the latter is fine. I'm using the latter in the code here. – Roi Danton Oct 17 '19 at 10:19
  • Please prove to me that `std::atoi` indeed throws an exception, by citing a suitable reference. Until you do, I don't believe you since it would be very confusing to have both `::atoi` and `std::atoi` acting in a completely different way. – Roland Illig Oct 17 '19 at 18:10
  • 5
    @RolandIllig Thanks for being persistent! You are right, it was an oversight that `std::atoi` was used instead of `std::stoi`. I've fixed that. – Roi Danton Oct 18 '19 at 12:05
  • This answer is the most modern way to do it. +1 for the use of `string_view`. Thanks for such a curated and robust code sample! – brita_ Aug 19 '20 at 06:02
26

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());
Community
  • 1
  • 1
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 8
    `rfind(x, 0) == 0` should really be defined in the standard as `starts_with` – porges Jul 01 '16 at 00:52
  • 1
    No, because `rfind()` (in place of `startswith()`) is very inefficient - it keeps searching till the end of the string. – ankostis Apr 24 '18 at 10:35
  • 4
    @ankostis rfind(x) searchs from the end till the start until it finds x, indeed. But rfind(x,0) starts searching from the start (position=0) till the start; so it only searches where it needs searching; does not search from/till the end. – Anonymous Coward Jul 15 '19 at 11:26
19

Starting with C++20, you can use the starts_with method.

std::string s = "abcd";
if (s.starts_with("abc")) {
    ...
}
Sam Kumar
  • 428
  • 4
  • 8
15
text.substr(0, start.length()) == start
rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
Macsinus
  • 167
  • 1
  • 7
  • 3
    @GregorDoroschenko it does answer the "check if string starts with another" part. – etarion Apr 13 '18 at 13:16
  • 2
    Efficient and elegant using std::string. I learnt the most from this. – Michael B Mar 23 '19 at 12:59
  • 1
    extra points for being a one-liner suitable for use with `if (one-liner)` – Adam.at.Epsilon Apr 11 '19 at 08:48
  • @Roland Illig Why do you believe that the behaviour in that case is undefined? The expression will return false because substr returns a string of the same length as text according to https://en.cppreference.com/w/cpp/string/basic_string/substr – Macsinus Jan 09 '20 at 07:36
12

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;
}
razvanco13
  • 121
  • 1
  • 3
11

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
  • 10,689
  • 4
  • 41
  • 50
  • 7
    If `argv[i]` is `"--foo=9999999999999999999999999"`, the behavior is undefined (though most or all implementations should behave sanely). I'm assuming `9999999999999999999999999 > INT_MAX`. – Keith Thompson Aug 22 '11 at 03:33
11

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;
}
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
11

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"});
Guss
  • 762
  • 4
  • 20
  • is there an upside to using a string_view of a literal here? (compared to just using a literal) – kritzikratzi Aug 14 '22 at 11:52
  • I'd rather use string-view-literals here https://en.cppreference.com/w/cpp/string/basic_string_view/operator%22%22sv using the `""sv` operator. – Guss Aug 15 '22 at 11:53
9

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="))
Felix Dombek
  • 13,664
  • 17
  • 79
  • 131
CM777
  • 431
  • 5
  • 5
6

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;
}
Parker
  • 7,244
  • 12
  • 70
  • 92
  • 1
    I like to use `::compare`, which gives identical result: `return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;` – Alexis Paques Sep 21 '20 at 09:03
5

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
Carl Cook
  • 372
  • 5
  • 8
3

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..

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
Nils
  • 13,319
  • 19
  • 86
  • 108
2

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'.

szx
  • 6,433
  • 6
  • 46
  • 67
2

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
}

Good luck!

Melroy van den Berg
  • 2,697
  • 28
  • 31
  • Why not rfind? rfind(str, 0) will not needlessly scan an entire string to make a selection as it cannot advance. See others. – user2864740 Dec 08 '19 at 23:10
  • @user2864740 Because `rfind` can lead to false positive since it "Find last occurrence of content in string". So "prefixblabla" matches but also "blablaprefixbla" would match. – Bemipefe Aug 25 '22 at 09:07
  • 1
    @merloy-van-den-berg according to this doc the `find_first_of` method is implemented or backported also on C++98: https://cplusplus.com/reference/string/string/find_first_of/ – Bemipefe Aug 25 '22 at 09:10
1
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;
}
mois
  • 119
  • 6
  • 3
    It would be great, if you avoid pasting code without code explanation. Thank you. – Malakai Oct 09 '17 at 08:05
  • 1
    Inefficient code, would continue searching past the start of the string. – ankostis Apr 24 '18 at 10:34
  • I was going to post the same thing. @Reborn Simple explanation: - This is the equivalent of saying if string start is found inside of string text at index 0 go into the if statement. - More specifically std::string find returns the first index of the original std::string that matches the string in parentheses. When it is equal to 0 it is the start of the string. – Aleksandr Jul 20 '21 at 20:33
  • @ankostis this code would be very efficient since it is optimized by the compiler and improved in subsequent compiler enhancements. – Aleksandr Jul 20 '21 at 20:33
0

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.

alextoind
  • 1,143
  • 1
  • 13
  • 20
0

C++20, use s.starts_with(), see link for examples:

https://en.cppreference.com/w/cpp/string/basic_string/starts_with

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
-4
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
  • 4,862
  • 2
  • 24
  • 23