Проверьте, является ли одна строка префиксом другой

у меня есть две строки, которые я хочу сравнить: String и String:. Есть ли библиотечная функция, которая возвращала бы true при передаче этих двух строк, но false для say String и OtherString?

чтобы быть точным, я хочу знать, является ли одна строка является префиксом другой.

12 ответов


использовать std::mismatch. Пройти в короткие строки, как первый итератор диапазона и уже как второй итератор диапазона. Возврат представляет собой пару итераторов, первый-итератор в первом диапазоне, а второй-во втором. Если первый является концом первого диапазона, то вы знаете, что короткая строка является префиксом более длинной строки, например

std::string foo("foo");
std::string foobar("foobar");

auto res = std::mismatch(foo.begin(), foo.end(), foobar.begin());

if (res.first == foo.end())
{
  // foo is a prefix of foobar.
}

Если вы знаете, какая строка короче, процедура проста, просто используйте std::equal С более короткой строкой первого. Если нет, то как должно работать следующее:

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() );
}

std::string(X).find(Y) равен нулю, если и только если Y является префиксом X


С string:: compare, вы должны уметь писать что-то вроде:

bool match = (0==s1.compare(0, min(s1.length(), s2.length()), s2,0,min(s1.length(),s2.length())));

кроме того, в случае, если мы не хотим использовать length() функции:

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;
}

Как насчет просто:

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++ не C, безопасный, простой, эффективный.

протестировано с:

#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;

}

если вы можете разумно игнорировать любые многобайтовые кодировки (скажем, UTF-8), тогда вы можете использовать strncmp для этого:

// 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;
}

если вы настаиваете на использовании причудливой версии c++, вы можете использовать std::equal алгоритм (с дополнительным преимуществом, что ваша функция также работает для других коллекций, а не только строк):

// 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() );
}

это и эффективно и удобно:

a.size() >= b.size() && a.compare(0, b.size(), b) == 0

С std::string на size деятельность нул-цена, и compare использует fast traits::compare метод.

обратите внимание, что без сравнения размеров, compare одного недостаточно, потому что он сравнивает только a.size() символы и "xyz" будет префиксом "xy".


самый простой способ-использовать substr () и сравнить() функции-члены:

string str = "Foobar";
string prefix = "Foo";

if(str.substr(0, prefix.size()).compare(prefix) == 0) cout<<"Found!";

Вы можете использовать это:

для c++14 или менее

bool has_prefix
    (std::string str, std::string prefix)  {
    return str.find(prefix, 0) == 0;
}

для c++17

//is much faster
auto has_prefix
    (std::string str, std::string_view prefix) -> decltype(str.find(prefix) == 0) {
    return str.find(prefix, 0) == 0;
}

str1 выглядит следующим образом.find (str2) возвращает 0, если весь str2 находится в индексе 0 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;
}

выход:

  str2 starts with str1
  str3 does not start with str1
  one is prefix of another
  one is not prefix of another

что не так с" find " и проверкой результата для позиции 0 ?

string a = "String";
string b = "String:";

if(b.find(a) == 0)
{
// Prefix

}
else
{
// No Prefix
}

Я думаю strncmp ближе всего к тому, что вы ищете.

хотя, если переформулировать, вы можете искать strstr(s2,s1)==s2, что не обязательно является самым эффективным способом сделать это. Но вы не хотите работать n ;-)

Хорошо, хорошо, версия C++ будет !s1.find(s2).

хорошо, вы можете сделать его еще больше c++, что-то вроде этого: std::mismatch(s1.begin(),s1.end(),s2.begin()).first==s1.end().