How do I check if a C++ std::string starts with a certain string, and convert a substring to an int?
Solution 1
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)
Solution 2
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.
Solution 3
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
ifstr
starts withsubstr
. The functionsstrncmp
andstrlen
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())
Solution 4
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.
Solution 5
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());
}
Daryl Spitzer
Father of three, husband, computer programmer (Pythonista), skeptic, atheist, podcast listener, baseball fan, Canadian (in the United States).
Updated on July 08, 2022Comments
-
Daryl Spitzer almost 2 years
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
, thenfoo_value
is98
.)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).
-
Tom over 14 yearsThe biggest problem with this is that
atoi("123xyz")
returns123
, whereas Python'sint("123xyz")
throws an exception. -
Roopesh Majeti over 14 yearsThe workaround, we can do, is to a sscanf() and compare the result and the original, to decide whether to proceed or throw exception.
-
Tom over 14 yearsOr just replace
atoi
withstrtol
orstrtoll
, which lets us detect error conditions in the input value. -
Keith Thompson over 12 yearsIf
argv[i]
is"--foo=9999999999999999999999999"
, the behavior is undefined (though most or all implementations should behave sanely). I'm assuming9999999999999999999999999 > INT_MAX
. -
Ben Bryant about 12 yearsthe most concise and only depends on std::string, except remove the optional and misleading argument.size() at the end of the final substr.
-
Hüseyin Yağlı about 12 years@ben-bryant: Thanks for the heads up. Didn't know it was optional.
-
cyrilchampier almost 12 years"boost::algorithm::starts_with" instead of "boost::starts_with" ?
-
Ferruccio almost 12 years@nerith: Seems they both work. I've always used the shorter form.
-
Jared Grubb over 11 yearsThat should be
if (prefix.size()<=arg.size() && std::equal(...))
. -
Alex Bitek over 11 yearsboost::starts_with and boost::algorithm::starts_with are the same thing. If you look at the end of this file svn.boost.org/svn/boost/trunk/boost/algorithm/string/… you will see this: // pull names to the boost namespace using algorithm::starts_with; [...]
-
Felix Dombek over 10 yearsUsing
substr
leads to unnecessary copying. Thestr.compare(start, count, substr)
method used in Thomas' answer is more efficient. razvanco13's answer has another method which avoids copying by usingstd::equal
. -
robertwb almost 10 yearsA lesson in history: plus.sandbox.google.com/+RobPikeTheHuman/posts/R58WgWwN9jp
-
Brice M. Dempsey almost 9 yearsWhy not use std::equal?
-
matiu almost 9 yearsSounds good to me. It would be shorter code too. I spose, I'll have to edit the answer now :p
-
Parthian Shot over 8 years@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 usingstrtol
or one of the other, related functions. Becauseatoi
has no error handling. But, again, that's only in C, anyway). -
Tobi almost 8 yearsPulling in huge dependencies for a string prefix check is like shooting birds with canons.
-
Felix Dombek almost 8 yearsUsing
std::equal
for strings has the downside that it doesn't detect the string end, so you need to manually check whether the prefix is shorter than the whole string. (As correctly done in the example prog, but omitted in the one-liner above.) -
porges almost 8 years
rfind(x, 0) == 0
should really be defined in the standard asstarts_with
-
Glenn Maynard over 7 years"Use Boost" is always the wrong answer when someone asks how to do a simple string operation in C++.
-
uglycoyote over 7 yearsminus 1 for suggesting Boost
-
osjerick about 7 yearsUsing boost here is right, if you already use boost in your project.
-
paxdiablo almost 7 years@sweisgerber.dev, I'm confused on your first contention. The return value from
find
will only be zero iftiti
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 getnpos
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). -
sweisgerber.dev almost 7 years@paxdiablo: you are right, it does indeed check if it starts with
titi
, but the conversion part is missing. -
Malakai over 6 yearsIt would be great, if you avoid pasting code without code explanation. Thank you.
-
Андрей Вахрушев over 6 yearsSo, no benefit over rfind?
-
qwattash over 6 yearsUsing 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.
-
NuSkooler over 6 yearsThe 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
-
etarion about 6 years@GregorDoroschenko it does answer the "check if string starts with another" part.
-
ankostis about 6 yearsInefficient code, would continue searching past the start of the string.
-
ankostis about 6 yearsNo, because
rfind()
(in place ofstartswith()
) is very inefficient - it keeps searching till the end of the string. -
Force Gaia about 6 yearsindeed, everyone seems to just go "use boost" and i for one am thankful for an stl or OS library version
-
Michael B about 5 yearsEfficient and elegant using std::string. I learnt the most from this.
-
Superziyi about 5 yearsDo 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.
-
Adam.at.Epsilon about 5 yearsextra points for being a one-liner suitable for use with
if (one-liner)
-
Ayxan Haqverdili almost 5 years@robertwb Google+ is no longer available
-
Anonymous Coward almost 5 years@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.
-
Avishai Y almost 5 yearsYes. However, it assumes the string has no null characters in it. If it is not the case - one should use
memcmp()
-
Calmarius over 4 yearsThis is better solution than the
rfind
one which depends on optimization to work. -
Adham Zahran over 4 yearswhy would anyone use anything other than this simple beautiful solution?
-
Roi Danton over 4 years@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? -
Roland Illig over 4 years
-
Roi Danton over 4 years@RolandIllig I'm referring to your first comment. It seems, you are mistakenly talking about
atoi
instead ofstd::atoi
. The first is unsafe to use, while the latter is fine. I'm using the latter in the code here. -
Roland Illig over 4 yearsPlease 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
andstd::atoi
acting in a completely different way. -
Roi Danton over 4 years@RolandIllig Thanks for being persistent! You are right, it was an oversight that
std::atoi
was used instead ofstd::stoi
. I've fixed that. -
user2864740 over 4 yearsWhy not rfind? rfind(str, 0) will not needlessly scan an entire string to make a selection as it cannot advance. See others.
-
Macsinus over 4 years@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 en.cppreference.com/w/cpp/string/basic_string/substr
-
Arthur Tacca almost 4 years@alcoforado "rfind will start from the back of the string ..." No, that only applies to the overload of
rfind()
that does not take apos
parameter. If you use the overload that does take apos
parameter then it will not search the whole string, only that position and earlier. (Just like regularfind()
withpos
parameter only looks in that position or later.) So if you passpos == 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. -
brita_ almost 4 yearsThis 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! -
Yuval over 3 years@Calmarius the
rfind
solution does not depend on any optimization.rfind
's behavior by definition is to only look at a single index when givenpos=0
, hence it is always an efficient check. Which syntax is more pleasant is a matter of preference. -
Alexis Paques over 3 yearsI like to use
::compare
, which gives identical result:return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
-
Jepessen over 3 yearsBoost 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 over 3 yearsBoost 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.
-
Aleksandr almost 3 yearsI 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 almost 3 years@ankostis this code would be very efficient since it is optimized by the compiler and improved in subsequent compiler enhancements.
-
Vishal Sahu over 2 years
that position or earlier
is the important phrase here.