'Check if one string is a prefix of another
I have two strings which I'd like to compare: String and String:. Is there a library function that would return true when passed these two strings, but false for say String and OtherString?
To be precise, I want to know whether one string is a prefix of another.
Solution 1:[1]
This is both efficient and convenient:
str.compare(0, pre.size(), pre) == 0
compare is fast because it uses the fast traits::compare method and doesn't have to copy any data.
Here, it will compare std::min(str.size(), pre.size()) characters but if the characters in the two ranges are equal it also checks the length of pre and returns a non-zero value if pre is longer than this.
See the documentation at cplusplus.com.
I've written a test program that uses this code to compare prefixes and strings given on the command line.
Solution 2:[2]
If you know which string is shorter, the procedure is simple, just use
std::equal with the shorter string first. If you don't, something
like the following should work:
bool
unorderIsPrefix( std::string const& lhs, std::string const& rhs )
{
return std::equal(
lhs.begin(),
lhs.begin() + std::min( lhs.size(), rhs.size() ),
rhs.begin() );
}
Solution 3:[3]
std::string(X).find(Y) is zero if and only if Y is a prefix of X
Solution 4:[4]
With string::compare, you should be able to write something like:
bool match = (0==s1.compare(0, min(s1.length(), s2.length()), s2,0,min(s1.length(),s2.length())));
Alternatively, in case we don't want to use the length() member function:
bool isPrefix(string const& s1, string const&s2)
{
const char*p = s1.c_str();
const char*q = s2.c_str();
while (*p&&*q)
if (*p++!=*q++)
return false;
return true;
}
Solution 5:[5]
If you can reasonably ignore any multi-byte encodings (say, UTF-8) then you can use strncmp for this:
// Yields true if the string 's' starts with the string 't'.
bool startsWith( const std::string &s, const std::string &t )
{
return strncmp( s.c_str(), t.c_str(), t.size() ) == 0;
}
If you insist on using a fancy C++ version, you can use the std::equal algorithm (with the added benefit that your function also works for other collections, not just strings):
// Yields true if the string 's' starts with the string 't'.
template <class T>
bool startsWith( const T &s, const T &t )
{
return s.size() >= t.size() &&
std::equal( t.begin(), t.end(), s.begin() );
}
Solution 6:[6]
After C++20, we can use starts_with to check if a string begins with given prefix.
str.starts_with(prefix)
Also, there is ends_with to check suffix
Solution 7:[7]
How about simply:
bool prefix(const std::string& a, const std::string& b) {
if (a.size() > b.size()) {
return a.substr(0,b.size()) == b;
}
else {
return b.substr(0,a.size()) == a;
}
}
C++ not C, safe, simple, efficient.
Tested with:
#include <string>
#include <iostream>
bool prefix(const std::string& a, const std::string& b);
int main() {
const std::string t1 = "test";
const std::string t2 = "testing";
const std::string t3 = "hello";
const std::string t4 = "hello world";
std::cout << prefix(t1,t2) << "," << prefix(t2,t1) << std::endl;
std::cout << prefix(t3,t4) << "," << prefix(t4,t3) << std::endl;
std::cout << prefix(t1,t4) << "," << prefix(t4,t1) << std::endl;
std::cout << prefix(t1,t3) << "," << prefix(t3,t1) << std::endl;
}
If you have C++17 you can write a better version of this, using std::string_view instead:
#include <string>
#include <string_view>
bool prefix(const std::string& a, const std::string& b) {
if (a.size() > b.size()) {
return std::string_view(a.c_str(),b.size()) == b;
}
else {
return std::string_view(b.c_str(),a.size()) == a;
}
}
With g++ 7 at -O3 this collapses to a single memcmp call, which is a fairly substantial improvement over the older version.
Solution 8:[8]
Easiest way is to use substr() and compare() member functions:
string str = "Foobar";
string prefix = "Foo";
if(str.substr(0, prefix.size()).compare(prefix) == 0) cout<<"Found!";
Solution 9:[9]
You can use this:
for c++14 or less
bool has_prefix
(const std::string& str, const std::string& prefix) {
return str.find(prefix, 0) == 0;
}
for c++17
//it's a little faster
auto has_prefix
(const std::string& str, const std::string_view& prefix) -> decltype(str.find(prefix) == 0) {
return str.find(prefix, 0) == 0;
}
Solution 10:[10]
I think strncmp is the closest to what you're looking for.
Though, if reworded, you may be looking for strstr(s2,s1)==s2, which is not necessarily the most performant way to do that. But you do not want to work out n ;-)
Okay, okay, the c++ version would be !s1.find(s2).
Okay, you can make it even more c++, something like this: std::mismatch(s1.begin(),s1.end(),s2.begin()).first==s1.end().
Solution 11:[11]
str1.find(str2) returns 0 if entire str2 is found at the index 0 of str1:
#include <string>
#include <iostream>
// does str1 have str2 as prefix?
bool StartsWith(const std::string& str1, const std::string& str2)
{
return (str1.find(str2)) ? false : true;
}
// is one of the strings prefix of the another?
bool IsOnePrefixOfAnother(const std::string& str1, const std::string& str2)
{
return (str1.find(str2) && str2.find(str1)) ? false : true;
}
int main()
{
std::string str1("String");
std::string str2("String:");
std::string str3("OtherString");
if(StartsWith(str2, str1))
{
std::cout << "str2 starts with str1" << std::endl;
}
else
{
std::cout << "str2 does not start with str1" << std::endl;
}
if(StartsWith(str3, str1))
{
std::cout << "str3 starts with str1" << std::endl;
}
else
{
std::cout << "str3 does not start with str1" << std::endl;
}
if(IsOnePrefixOfAnother(str2, str1))
{
std::cout << "one is prefix of another" << std::endl;
}
else
{
std::cout << "one is not prefix of another" << std::endl;
}
if(IsOnePrefixOfAnother(str3, str1))
{
std::cout << "one is prefix of another" << std::endl;
}
else
{
std::cout << "one is not prefix of another" << std::endl;
}
return 0;
}
Output:
str2 starts with str1
str3 does not start with str1
one is prefix of another
one is not prefix of another
Solution 12:[12]
What's wrong with the "find" and checking the result for position 0 ?
string a = "String";
string b = "String:";
if(b.find(a) == 0)
{
// Prefix
}
else
{
// No Prefix
}
Solution 13:[13]
bool IsPrefix(const std::string& prefix, const std::string& whole)
{
return whole.size() >= prefix.size() && whole.compare(0, prefix.size(), prefix) == 0;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
